java - NIO2:如何将 URI 一般映射到路径?

标签 java jar filesystems zip nio2

我正在尝试找到一种简单的方法将 URI 映射到 Path 而无需编写特定于任何特定文件系统的代码。以下似乎可行,但需要一种有问题的技术:

public void process(URI uri) throws IOException {
    try {
        // First try getting a path via existing file systems. (default fs)
        Path path = Paths.get(uri);
        doSomething(uri, path);
    }
    catch (FileSystemNotFoundException e) {
        // No existing file system, so try creating one. (jars, zips, etc.)
        Map<String, ?> env = Collections.emptyMap();
        try (FileSystem fs = FileSystems.newFileSystem(uri, env)) {
            Path path = fs.provider().getPath(uri);  // yuck :(
            // assert path.getFileSystem() == fs;
            doSomething(uri, path);
        }
    }
}

private void doSomething(URI uri, Path path) {
    FileSystem fs = path.getFileSystem();
    System.out.println(uri);
    System.out.println("[" + fs.getClass().getSimpleName() + "] " + path);
}

在几个示例上运行此代码会产生以下结果:

file:/C:/Users/cambecc/target/classes/org/foo
[WindowsFileSystem] C:\Users\cambecc\target\classes\org\foo

jar:file:/C:/Users/cambecc/bin/utils-1.0.jar!/org/foo
[ZipFileSystem] /org/foo

请注意 URI 是如何映射到 Path 对象的,这些对象已“ Root ”到正确类型的 FileSystem 中,例如引用 jar 内目录“/org/foo”的路径。

这段代码让我困扰的是,尽管 NIO2 使它很容易:

  • 将 URI 映射到现有 文件系统中的路径:Paths.get(URI)
  • 将 URI 映射到 FileSystem 实例:FileSystems.newFileSystem(uri, env)

...在 FileSystem 实例中没有将 URI 映射到路径的好方法。

我能找到的最好的方法是,在创建文件系统后,我可以请求它的 FileSystemProvider 给我路径:

Path path = fs.provider().getPath(uri);

但这似乎是错误的,因为不能保证它会返回绑定(bind)到我刚刚实例化的文件系统的路径(即 path.getFileSystem() == fs)。它几乎依赖于 FileSystemProvider 的内部状态来了解我指的是什么 FileSystem 实例。有没有更好的办法?

最佳答案

您在 zipfs 的实现/文档中发现了一个错误。Path.get 方法的文档指出:

* @throws  FileSystemNotFoundException
*          The file system, identified by the URI, does not exist and
*          cannot be created automatically

编辑:对于需要关闭的文件系统,最好要求程序员调用 newFileSystem 以便他可以关闭它。文档应该更好地阅读“如果它不应该自动创建”。

ZipFs 从不尝试创建新的文件系统。失败的 get() 不会被捕获,而是在尝试调用 newFileSystem 之前传递给调用者。见源码:

public Path getPath(URI uri) {

    String spec = uri.getSchemeSpecificPart();
    int sep = spec.indexOf("!/");
    if (sep == -1)
        throw new IllegalArgumentException("URI: "
            + uri
            + " does not contain path info ex. jar:file:/c:/foo.zip!/BAR");
    return getFileSystem(uri).getPath(spec.substring(sep + 1));
}

换句话说:

Paths.get()

对于所有基于 nio2 的文件系统应该足够了。 使用 zipfs 设计。

Path path;
try {
   path = Paths.get( uri );
} catch ( FileSystemNotFoundException exp ) {
   try( FileSystem fs = FileSystems.newFileSystem( uri, Collections.EMPTY_MAP )) {;
       path = Paths.get( uri );
       ... use path ...
   }
}   

是您的解决方法的简短形式。

注意:nio 文档指出 getFileSystem 必须使用/返回由匹配的 newFileSystem 创建的文件系统。

关于java - NIO2:如何将 URI 一般映射到路径?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15195890/

相关文章:

java - IntellIj IDEA 找不到源文件

java - 使用从 jar 导入的类编译 java 时出错

java - Android - 复制文件后关闭电源导致文件损坏

java - 文件写入异步发生?

java - 具有多个图像的 Jpanel - 内存使用情况

java - 将对象引用存储到 volatile 字段中

java - SQL 脚本转换为 XML 格式

java - 如何从 jar 而不是 .java 文件在 S3 上创建私有(private) Maven 存储库?

linux - Linux 中的文件输出重定向

java - 安排多个重复警报