代码之家  ›  专栏  ›  技术社区  ›  cambecc

NIO2:如何将URI一般映射到Path?

  •  3
  • cambecc  · 技术社区  · 13 年前

    我正试图找到一种简单的方法来绘制 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
    

    请注意 乌里 s已映射到 路径 已经“扎根”到正确类型的对象 FileSystem ,类似于引用jar中目录“.org/foo”的Path。

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

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

    …没有一种很好的方法可以将URI映射到 文件系统 例子

    我能找到的最好的方法是,在创建了一个文件系统之后,我可以问它 FileSystemProvider 给我路径:

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

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

    2 回复  |  直到 13 年前
        1
  •  5
  •   openCage    13 年前

    您在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的文件系统来说应该足够了。 拉链设计。

    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创建的FileSystems。

        2
  •  2
  •   openCage    13 年前

    Q: “我正试图找到一种简单的方法,将URI映射到Path,而无需编写特定于任何特定文件系统的代码”

    A: 没有这样的办法

    只有当与URI关联的文件系统尚未打开时,即getFileSystem(在Paths.get中)抛出FileSystemNotFoundException时,整个问题才有意思。 但要调用newFileSystem,您需要知道两件事:

    • 用于创建新文件系统的URI(的一部分)。docu表示,即在默认文件系统的情况下,URI的路径组件必须是根。例如getFileSystem(URI.create(“file:///duda“,Collections.EMPTY_MAP)失败。
    • 在环境映射中设置什么,例如可能是密码。

    因此,要从URI创建新的文件系统,您必须了解要创建的文件系统。