简体   繁体   English

如果路径中包含空格,则Zip中文件的URI不正确

[英]URI to file in Zip incorrect if path contains spaces

I want to get the URIs to the entries of a zip file in order to keep references to it's contents without having to keep the zip file open. 我想获取zip文件条目的URI,以保持对其内容的引用,而不必保持zip文件打开。

Therefore I open the zip file using the zip filesystem and export the Path of the entries as URI. 因此,我使用zip文件系统打开了zip文件,并将条目的路径导出为URI。

Path zipfile = ...
URI uriOfFileInZip;
try(FileSystem fs = FileSystems.newFileSystem(zipfile, null)){
   Path fileInZip = fs.getPath("fileInZip.txt");
   uriOfFileInZip = fileInZip.toUri();
}

Now I want to read the file again, so I try to open a stream to the file. 现在,我想再次读取文件,因此尝试打开文件流。

InputStream is = uriOfFileInZip.toURL().openStream();

This works as long as the path of the zip file does not contain any spaces. 只要zip文件的路径不包含任何空格,它就可以工作。 As soon as it contains spaces, I get an error like this 一旦包含空格,就会出现这样的错误

java.io.FileNotFoundException: D:\example\name%20of%20zipfile.zip (The system cannot find the file specified)

the URI to the file in the zip is 压缩文件中的URI为

jar:file:///D:/example/name%2520of%2520zipfile.zip!/fileInZip.txt

the name of the zip is 邮编的名称是

D:\example\name of zipfile.zip

I wonder about the %2520 this seems like an issue with the URL encoding, but shouldn't this be handled transparently? 我对%2520感到疑惑,这似乎是URL编码的问题,但是这不应该透明地处理吗? Or is it a bug? 还是一个错误?

Any ideas to solve this problem? 有解决这个问题的想法吗?

Looks like a bug. 看起来像个错误。

Seems as if com.sun.nio.zipfs.ZipPath.toUri() is either messed up, or I didn't read the corresponding RFC yet ;-). 好像com.sun.nio.zipfs.ZipPath.toUri()搞砸了,或者我还没有阅读相应的RFC ;-)。 Played around with some other file names. 播放了其他一些文件名。 There seems to be a double encoding going on for the zip file path, but not for the file entry in the zip. 似乎zip文件路径有双重编码,但zip中的文件入口却没有。 Besides not using the URI-approach you could also build the URI yourself from scratch, but then you are not that flexible anymore. 除了不使用URI方法外,您还可以自己重新构建URI,但是那样就不那么灵活了。 Or you just undo the unnecessary encoding: 或者您只是撤消不必要的编码:

String uriParts[] = uriOfFileInZip.toString().split("!");
uriParts[0] = URLDecoder.decode(uriParts[0], "UTF-8");
uriOfFileInZip = URI.create(String.join("!", uriParts));

But to be honest, I would rather try to omit the URI for zip files or if you really have to, rename the files beforehand ;-) Better yet: open a bug if it does not behave as stated in the corresponding RFCs. 但老实说,我宁愿尝试省略zip文件的URI,或者如果确实需要,请事先对文件进行重命名;-)更好的是:如果错误行为不符合相应RFC中所述,则打开一个错误。

You may also want to get some additional information from the following question regarding bug, etc.: Java 7 zip file system provider doesn't seem to accept spaces in URI 您可能还希望从以下有关错误等的问题中获取一些其他信息: Java 7 zip文件系统提供程序似乎不接受URI中的空格

EDIT (added proposal without URI): 编辑(添加的提案,不带URI):

You can also try to completely work with your Path instance ( fileInZip ) instead of the URI, as the path instance "knows" its filesystem. 您还可以尝试完全使用Path实例( fileInZip )而不是URI,因为路径实例“知道”其文件系统。 As soon as you need access to the file inside the zip, you create a new FileSystem based on the information of the Path instance ( fileInZip.getFileSystem() ). 一旦需要访问zip文件中的文件, fileInZip.getFileSystem()基于Path实例的信息( fileInZip.getFileSystem() )创建一个新的FileSystem。 I did not elaborate that completely, but at least the file store should contain all the necessary information to access the zip file again. 我没有详细说明,但是至少文件存储应该包含所有必要的信息以再次访问zip文件。 With that information you could call something like FileSystems.newFileSystem(Paths.get(fileStoreName), null) . 有了这些信息,您可以调用类似FileSystems.newFileSystem(Paths.get(fileStoreName), null) Then you can also use Files.newInputStream(fileInZip) to create your InputStream . 然后,您还可以使用Files.newInputStream(fileInZip)创建您的InputStream No need to use URI here. 无需在此处使用URI。

This is only reproducible with JDK 8 . 这仅在JDK 8可以重现。 The later versions do not have this issue. 更高版本没有此问题。 For the following code: 对于以下代码:

Map<String, String> env = new HashMap<>(); 
env.put("create", "true");
final FileSystem fs = FileSystems.newFileSystem(new URI("jar:file:/D:/path%20with%20spaces/junit-4.5.jar"), env);
System.out.println(fs.getPath("LICENSE.TXT").toUri()); `

I got the following output with JDK 1.8.0_212 : 我使用JDK 1.8.0_212得到了以下输出:

jar:file:///D:/path%2520with%2520spaces/junit-4.5.jar!/LICENSE.TXT 

whereas with JDK 11.0.3 : 而使用JDK 11.0.3

jar:file:///D:/path%20with%20spaces/junit-4.5.jar!/LICENSE.TXT

A search through the Java bug system shows that it had been fixed in JDK 9 with JDK-8131067 . Java错误系统中进行的搜索显示,该错误已在JDK 9通过JDK-8131067修复

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM