Как создать объект FileSystem для * директории *, используя абсолютный путь? - PullRequest
0 голосов
/ 03 сентября 2018

Я создаю приложение командной строки, которое должно выводить некоторые файлы (более одного) в ZIP-файл или обычную папку в зависимости от заданных параметров.

Мой подход заключается в инкапсуляции цели (обычная папка / ZIP-файл) с FileSystem.

Моя проблема в том, что я не могу успешно создать 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 ?

1 Ответ

0 голосов
/ 04 сентября 2018

Не существует встроенного средства для создания FileSystem с chroot подобной семантикой. Файловая система по умолчанию поддерживает только 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.

...