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

时间:2016-06-21 06:00:36

标签: java zip uri zipfile

我想获取zip文件条目的URI,以便在不必保持zip文件打开的情况下保持对其内容的引用。

因此,我使用zip文件系统打开zip文件,并将条目的路径导出为URI。

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

现在我想再次阅读该文件,所以我尝试打开一个文件流。

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

只要 zip 文件的路径不包含任何空格,此方法就可以正常工作。只要它包含空格,我就会收到类似这样的错误

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

zip中文件的URI是

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

zip的名称是

D:\example\name of zipfile.zip

我想知道%2520这似乎是URL编码的一个问题,但是不应该透明地处理这个问题吗?或者这是一个错误?

有什么想法可以解决这个问题吗?

2 个答案:

答案 0 :(得分:2)

看起来像个错误。

似乎com.sun.nio.zipfs.ZipPath.toUri()要么搞砸了,要么我还没有阅读相应的RFC ;-)。玩了一些其他文件名。 zip文件路径似乎有双重编码,但zip中的文件条目没有。 除了不使用URI方法之外,您还可以从头开始构建URI,但之后您就不再那么灵活了。或者你只需​​撤消不必要的编码:

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

但说实话,我宁愿尝试省略zip文件的URI,或者如果你真的需要,请事先重命名文件;-)更好的是:如果它没有在相应的RFC中说明的话,请打开一个bug

您可能还希望从以下有关错误等的问题中获取一些其他信息: Java 7 zip file system provider doesn't seem to accept spaces in URI

编辑(添加了没有URI的提案):

您还可以尝试完全使用Path实例(fileInZip)而不是URI,因为路径实例"知道"它的文件系统。 只要您需要访问zip中的文件,就可以根据Path实例(fileInZip.getFileSystem())的信息创建新的FileSystem。我没有详细说明,但至少文件存储应该包含再次访问zip文件的所有必要信息。有了这些信息,您可以调用类似FileSystems.newFileSystem(Paths.get(fileStoreName), null)的内容。 然后,您还可以使用Files.newInputStream(fileInZip)创建InputStream。这里不需要使用URI。

答案 1 :(得分:1)

这只能用JDK 8复制。更高版本没有此问题。 对于以下代码:

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()); `

我用JDK 1.8.0_212得到了以下输出:

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

JDK 11.0.3

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

通过搜索Java bug system可以发现它已在JDK 9中用JDK-8131067修复了。