【问题标题】:How to create a FileSystem object for a *directory* using an absolute path?如何使用绝对路径为 *directory* 创建 FileSystem 对象?
【发布时间】:2019-02-08 06:55:36
【问题描述】:

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

我的方法是用FileSystem 封装目标(普通文件夹/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)

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

那么如何为 pwd 以外的目录 创建FileSystem 对象?

【问题讨论】:

  • 鉴于您的要求(第一句话),我认为java.nio.file.FileSystem 不是一个有用的方法。为什么不使用java.io.Filejava.util.zip.ZipFile
  • @Würgspaß 因为有不同的方法来创建一个新的“文件”。我不希望代码实际创建需要知道使用什么目标的文件。 (所有文件都应该放在同一个 ZIP 或目录中)
  • 创建新文件系统需要适当的文件系统提供程序实现。 JDK没有自带这样的目录封装文件系统。
  • @Holger 那么FileSystems.getDefault() 如何以root 身份返回pwd
  • FileSystems.getDefault() 确实使用密码作为根。调用FileSystems.getDefault().getRootDirectories() 时会得到根目录。您所做的只是解析相对路径,这总是针对当前目录发生的。这不会使它成为一个根。您仍然可以解析相关路径,例如 ..,或者在 Windows 的情况下,。在这方面,FileSystems.getDefault().getPath("test.file")Paths.get("test.file") 没有区别。

标签: java java-io java.nio.file


【解决方案1】:

没有用于创建具有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 实例仍然绑定到特定的文件系统,代码调用toString(),然后将其传递给targetBase.resolve(…),以确保它可以跨不同的文件系统工作。请注意,path.resolve(string) 等价于 path.resolve(path.getFileSystem().getPath(string))。如果该方法首先检查两个Path 实例是否属于同一个文件系统,那么在这种情况下跳过String 绕道是合法的。

【讨论】:

    猜你喜欢
    • 2012-09-20
    • 1970-01-01
    • 1970-01-01
    • 2022-06-19
    • 1970-01-01
    • 2019-04-10
    • 1970-01-01
    • 1970-01-01
    • 2013-04-10
    相关资源
    最近更新 更多