如何使用绝对路径为 *directory* 创建 FileSystem 对象?

How to create a FileSystem object for a *directory* using an absolute path?

我正在创建一个命令行应用程序,它需要将一些文件(多个)输出到 ZIP 文件 普通文件夹 取决于给定的参数。

我的方法是用 FileSystem.

封装目标(普通 folder/ZIP 文件)

我的问题是我无法成功地为 目录 创建一个 FileSystem 对象而不是 当前工作目录 表示我硬盘上的 绝对路径:

public class FileSystemWriteTest {
    public static void main(String[] args) throws IOException {
        Path absolutePath = Paths.get("target", "testpath").toAbsolutePath();
        System.out.println(String.format("user.dir before change:\n %s", System.getProperty("user.dir")));


        System.setProperty("user.dir", absolutePath.toString());
        System.out.println(String.format("changed user.dir:\n %s", System.getProperty("user.dir")));
        FileSystem defaultSystem = FileSystems.getDefault();
        Path testFilePath = defaultSystem.getPath("test.file");
        System.out.println(String.format("expected to be in changed user.dir:\n %s", testFilePath.toAbsolutePath()));


        URI uri = absolutePath.toUri();
        System.out.println(String.format("URI: %s", uri));
        FileSystem localFileSystem =
                FileSystems.newFileSystem(uri, Collections.emptyMap());
        Path file = localFileSystem.getPath("test.txt");
        System.out.println(file.toAbsolutePath());
    }
}

输出为:

user.dir before change:
 D:\data\scm-workspace\anderes\Test
changed user.dir:
 D:\data\scm-workspace\anderes\Test\target\testpath
expected to be in changed user.dir:
 D:\data\scm-workspace\anderes\Test\test.file
URI: file:///D:/data/scm-workspace/anderes/Test/target/testpath/
Exception in thread "main" java.lang.IllegalArgumentException: Path component should be '/'
    at sun.nio.fs.WindowsFileSystemProvider.checkUri(Unknown Source)
    at sun.nio.fs.WindowsFileSystemProvider.newFileSystem(Unknown Source)
    at java.nio.file.FileSystems.newFileSystem(Unknown Source)
    at java.nio.file.FileSystems.newFileSystem(Unknown Source)
    at com.oc.test.filesystem.FileSystemWriteTest.main(FileSystemWriteTest.java:27)

如果我更改为 FileSystems.newFileSystem(Path, Classloader),异常将更改为:

Exception in thread "main" java.nio.file.ProviderNotFoundException: Provider not found
    at java.nio.file.FileSystems.newFileSystem(Unknown Source)
    at com.oc.test.filesystem.FileSystemWriteTest.main(FileSystemWriteTest.java:27)

看起来这只适用于常规文件,不适用于目录

那么如何为 目录 创建一个 FileSystem 对象而不是 pwd

没有用于创建具有 chroot 之类语义的 FileSystem 的内置工具。默认文件系统仅支持 file:/// 作为 URI,并且不允许超过一个实例化。

在这方面,FileSystems.getDefault().getPath("test.file")创建了一个相对路径,就像Paths.get("test.file")一样。为默认文件系统和其他文件系统创建的相对路径之间的区别在于未指定其他基本路径时的解析行为(例如,当调用 toAbsolutePath() 或只是试图打开它们时)。但是针对当前工作目录进行解析不会使它们成为根路径。

实现文件系统不可知操作的最佳解决方案是让代码接收基础 Path 对象,以解析相对路径。

例如一个简单的树复制例程可能如下所示:

static void copyTree(Path sourceBase, Path targetBase) throws IOException {
    try {
        Files.walk(sourceBase).forEach(path -> {
            if(Files.isRegularFile(path)) try {
                Path target = targetBase.resolve(sourceBase.relativize(path).toString());
                if(!Files.isDirectory(target.getParent()))
                    Files.createDirectories(target.getParent());
                Files.copy(path, target, StandardCopyOption.COPY_ATTRIBUTES);
            } catch(IOException ex) {
                throw new UncheckedIOException(ex);
            }
        });
    } catch(UncheckedIOException ex) {
        throw ex.getCause();
    }
}

对于这种方法,无论您是从一个硬盘驱动器目录复制到另一个硬盘驱动器目录,还是复制到一个 zip 文件系统,或者从一个 zip 文件系统复制到硬盘驱动器,或者从一个 zip 文件复制到另一个 zip 文件,都没有关系文件等

最有趣的部分是sourceBase.relativize(path)的调用,以获取从源基本路径到实际文件子路径的相对路径。由于相对 Path 实例仍然绑定到特定的文件系统,因此代码在将其传递给 targetBase.resolve(…) 之前调用 toString(),以确保它可以跨不同的文件系统工作。请注意 path.resolve(string) 等同于 path.resolve(path.getFileSystem().getPath(string))。如果该方法首先检查两个 Path 实例是否属于同一个文件系统,那么在这种情况下跳过 String 弯路是合法的。