Java 7 zip 文件系统提供程序似乎不接受 URI 中的空格

2022-09-02 04:25:21

我一直在测试所有可能的变体和排列,但我似乎无法使用包含空格的路径(URI)的zip/jar方案构建FileSystemProvider。Oracle Docs上有一个非常简单的测试用例。我冒昧地修改了示例,只是向URI添加空格,然后它就停止工作了。下面的片段:

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)) {}
        }
    }
}

当我执行此代码(Windows,JDK7u2,x32和x64)时,我得到以下异常:

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)

如果我使用 + 而不是 %20 作为空格转义字符,则会引发不同的异常:

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)

我可能错过了一些非常明显的东西,但这是否表明提供的ZIP / JAR文件系统提供程序存在问题?

编辑:

另一个基于 File 对象的用例,如 coments 中所请求的:

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

异常再次引发,如下所示:

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)

答案 1

实际上,进一步的分析似乎表明ZipFileSystemProvider存在问题。该类中包含的 uriToPath(URI uri) 方法执行以下代码段:

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

从URI.getSchemeSpecificPart()的JavaDocs中,我们可以看到以下内容:

此方法返回的字符串等于 getRawSchemeSpecificPart 方法返回的字符串,只是所有转义八位字节的序列都已解码

然后,将此相同的字符串作为参数传递回新的 URI() 构造函数。由于任何转义的八位字节都由 getSchemeSpecificPart() 取消转义,因此如果原始 URI 包含任何转义字符,则它们不会传播到新的 URI - 因此例外。

一个潜在的解决方法 - 遍历所有可用的文件系统提供程序,并获取对规范等于“jar”的那个提供程序的引用。然后使用它来创建一个仅基于路径的新文件系统。


答案 2

这是 Java 7 中的一个错误,它已在 Java 8 中标记为已修复(请参阅 bug ID 7156873)。该修复程序也应该向后移植到 Java 7,但目前尚未确定哪个更新将具有它(请参阅 bug ID 8001178)。


推荐