我想获取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编码的一个问题,但是不应该透明地处理这个问题吗?或者这是一个错误?
有什么想法可以解决这个问题吗?
答案 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修复了。