问题
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.
Therefore I open the zip file using the zip filesystem and export the Path of the entries as 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. 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
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? Or is it a bug?
Any ideas to solve this problem?
回答1:
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 ;-). 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.
Besides not using the URI-approach you could also build the URI yourself from scratch, but then you are not that flexible anymore. 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.
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
EDIT (added proposal without URI):
You can also try to completely work with your Path instance (fileInZip
) instead of the URI, as the path instance "knows" its filesystem.
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()
). I did not elaborate that completely, but at least the file store should contain all the necessary information to access the zip file again. With that information you could call something like FileSystems.newFileSystem(Paths.get(fileStoreName), null)
.
Then you can also use Files.newInputStream(fileInZip)
to create your InputStream
. No need to use URI here.
回答2:
This is only reproducible with 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
:
jar:file:///D:/path%2520with%2520spaces/junit-4.5.jar!/LICENSE.TXT
whereas with 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 .
来源:https://stackoverflow.com/questions/37936627/uri-to-file-in-zip-incorrect-if-path-contains-spaces