Java 7 zip server file system provider doesn't seem to accept spaces in URI

I tested all possible options and permutations, but I cannot build a FileSystemProvider using the zip / jar scheme for a path (URI) that contains spaces. There is a very simplified test available in Oracle Docs . I let the example change and just add spaces to the URI, and it stops working. The snapshot below:

import java.util.*; import java.net.URI; import java.nio.file.*; public class Test { public static void main(String [] args) throws Throwable { Map<String, String> env = new HashMap<>(); env.put("create", "true"); URI uri = new URI("jar:file:/c:/dir%20with%20spaces/zipfstest.zip"); Path dir = Paths.get("C:\\dir with spaces"); if(Files.exists(dir) && Files.isDirectory(dir)) { try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) {} } } } 

When I execute this code (Windows, JDK7u2, both x32 and x64), I get the following exception:

 java.lang.IllegalArgumentException: Illegal character in path at index 12: file:/c:/dir with spaces/zipfstest.zip at com.sun.nio.zipfs.ZipFileSystemProvider.uriToPath(ZipFileSystemProvider.java:87) at com.sun.nio.zipfs.ZipFileSystemProvider.newFileSystem(ZipFileSystemProvider.java:107) at java.nio.file.FileSystems.newFileSystem(FileSystems.java:322) at java.nio.file.FileSystems.newFileSystem(FileSystems.java:272) 

If I use + instead of% 20 as a space escape character, another exception is thrown:

 java.nio.file.NoSuchFileException: c:\dir+with+spaces\zipfstest.zip at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:79) at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97) at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102) at sun.nio.fs.WindowsFileSystemProvider.newByteChannel(WindowsFileSystemProvider.java:229) at java.nio.file.spi.FileSystemProvider.newOutputStream(FileSystemProvider.java:430) at java.nio.file.Files.newOutputStream(Files.java:170) at com.sun.nio.zipfs.ZipFileSystem.<init>(ZipFileSystem.java:116) at com.sun.nio.zipfs.ZipFileSystemProvider.newFileSystem(ZipFileSystemProvider.java:117) at java.nio.file.FileSystems.newFileSystem(FileSystems.java:322) at java.nio.file.FileSystems.newFileSystem(FileSystems.java:272) 

I might have missed something very obvious, but would this indicate a problem with the provided ZIP / JAR file system provider?

EDIT:

Another use case based on a File object, as requested in the comments:

 import java.io.File; import java.io.UnsupportedEncodingException; import java.net.URI; import java.nio.file.FileSystems; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; public class Test { public static void main(String[] args) throws UnsupportedEncodingException { try { File zip = new File("C:\\dir with spaces\\file.zip"); URI uri = URI.create("jar:" + zip.toURI().toURL()); Map<String, String> env = new HashMap<>(); env.put("create", "true"); if(zip.getParentFile().exists() && zip.getParentFile().isDirectory()) { FileSystems.newFileSystem(uri, env); } } catch (Exception ex) { Logger.getAnonymousLogger().log(Level.SEVERE, null, ex); System.out.println(); } } } 

The exception is repeated as:

 java.lang.IllegalArgumentException: Illegal character in path at index 12: file:/C:/dir with spaces/file.zip at com.sun.nio.zipfs.ZipFileSystemProvider.uriToPath(ZipFileSystemProvider.java:87) at com.sun.nio.zipfs.ZipFileSystemProvider.newFileSystem(ZipFileSystemProvider.java:107) at java.nio.file.FileSystems.newFileSystem(FileSystems.java:322) at java.nio.file.FileSystems.newFileSystem(FileSystems.java:272) 
+20
java java-7
Mar 26 2018-12-12T00:
source share
4 answers

In fact, further analysis seems to indicate a problem with ZipFileSystemProvider. The uriToPath (uri uri) method contained within the class executes the following snippet:

 String spec = uri.getSchemeSpecificPart(); int sep = spec.indexOf("!/"); if (sep != -1) spec = spec.substring(0, sep); return Paths.get(new URI(spec)).toAbsolutePath(); 

From the JavaDocs URI.getSchemeSpecificPart () we can see the following:

The string returned by this method is equal to that returned by getRawSchemeSpecificPart, except that all sequences of escaped octets are decoded .

The same string is then passed back as an argument to the new URI () constructor. Since any escaped octets are removed using getSchemeSpecificPart (), if the source URI contains any escape characters, they will not propagate to the new URI - hence the exception.

A potential workaround is to bypass all available file system providers and get a link to those who specify the "jar". Then use this to create a new file system based only on the path.

+6
Mar 26 2018-12-12T00:
source share

This is a bug in Java 7, and it has been flagged as fixed in Java 8 (see bug ID 7156873 ). The fix should also be addressed to Java 7, but at the moment it has not determined which update will have it (see Error ID 8001178 ).

+5
Dec 25
source share

jar: URIs must have escaped zip-URIs in their schema-specific part, so your jar: URI is just wrong - it should be fairly double escaped, since the jar: scheme consists of the host URI,! / and the local path.

However, this escaping is implied and not expressed in the minimum "URL specification" in the JarURLConnection . I agree, however, with the increased error in the JRE that it should still accept single screens, although this may lead to some strange edge cases not being supported.

As noted by tornike and evermean in another answer, the easiest way is to do FileSystems.newFileSystem (path, null) - but this does not work when you want to go and env with say "create" = true.

Instead, create a jar: URI using a component-based constructor:

 URI jar = new URI("jar", path.toUri().toString(), null); 

This will correctly encode the part related to the circuit.

Like the JUnit test, which also confirms that this is the escaping used when opening from the path:

 @Test public void jarWithSpaces() throws Exception { Path path = Files.createTempFile("with several spaces", ".zip"); Files.delete(path); // Will fail with FileSystemNotFoundException without env: //FileSystems.newFileSystem(path, null); // Neither does this work, as it does not double-escape: // URI jar = URI.create("jar:" + path.toUri().toASCIIString()); URI jar = new URI("jar", path.toUri().toString(), null); assertTrue(jar.toASCIIString().contains("with%2520several%2520spaces")); Map<String, Object> env = new HashMap<>(); env.put("create", "true"); try (FileSystem fs = FileSystems.newFileSystem(jar, env)) { URI root = fs.getPath("/").toUri(); assertTrue(root.toString().contains("with%2520several%2520spaces")); } // Reopen from now-existing Path to check that the URI is // escaped in the same way try (FileSystem fs = FileSystems.newFileSystem(path, null)) { URI root = fs.getPath("/").toUri(); //System.out.println(root.toASCIIString()); assertTrue(root.toString().contains("with%2520several%2520spaces")); } } 

(I did a similar test with "with \ u2301unicode \ u263bhere" to verify that I do not need to use .toASCIIString ())

+4
May 16 '13 at 10:14
source share

There are two ways to create a file system:

FileSystem fs = FileSystems.newFileSystem(uri, env);

FileSystem fs = FileSystems.newFileSystem(zipfile, null);

If there is a place in the file name along with the above solution for creating uri. It also works if you use another method that does not accept uri as an argument.

+3
Mar 05
source share



All Articles