Как я могу определить канонический путь к файлу без перехода по символическим ссылкам?

Предположим, у меня есть следующие объекты java.io.File и соответствующие объекты java.nio.file.Path:

final String windir = "WINNT";
final String comspec = "cmd.exe";
final File absoluteFile = new File(format("C:\\./foo/../bar/../%s/./././././SYSTEM32/../system/../System32/%s", windir, comspec)).getAbsoluteFile();
final Path absolutePath = absoluteFile.toPath();

Теперь я хочу определить канонический путь, т.е. е. удалите все записи пути . или .., чтобы результирующий путь был C:\WINNT\System32\cmd.exe.

java.io.File.getCanonicalPath() подходит, за исключением того, что он следует символическим ссылкам на Unices, которых я хотел бы избежать.

java.nio.file.Path.toRealPath(NOFOLLOW_LINKS), с другой стороны, возвращает канонический путь без перехода по символическим ссылкам, но выдает ошибку java.nio.file.NoSuchFileException.

Как определить канонический путь к файлу

  • безопасным способом (чтобы не возникало исключений в случае, если файл не существует),
  • независимо от платформы и
  • без перехода по символическим ссылкам?

Единственное решение, которое я нашел до сих пор, — это вернуться к старому java.io API:

@NonNull Path toCanonicalPath(final @NonNull Path path) throws IOException {
    try {
        /*
         * Fails for nonexistent files.
         */
        return path.toRealPath(NOFOLLOW_LINKS);
    } catch (final NoSuchFileException ignored) {
        /*
         * This one is fine except it always follows symbolic links on Unices.
         */
        return path.toFile().getCanonicalFile().toPath();
    } catch (final FileSystemException ignored) {
        /*
         * Thrown when there's a file/directory conflict, e. g.
         * for a non-existent file "foo/bar", "foo" already
         * exists and is a symlink, not a directory. In this
         * case, we can't use the File#getCanonicalFile() call.
         */
        return path.toAbsolutePath();
    }
}

Есть ли менее уродливый подход?


person Bass    schedule 29.08.2017    source источник
comment
Я не понимаю, как можно получить канонический путь без перехода по символическим ссылкам. Он определен как разрешение символических ссылок. (Хорошо, он также определяется как уникальный, что может быть не так в Unix и Unix-подобных системах...)   -  person Andrew Henle    schedule 29.08.2017
comment
@AndrewHenle Canonical с точки зрения удаления любых записей пути . или .., т.е. е. Мне нужен кратчайший абсолютный путь (но без разрешения символической ссылки).   -  person Bass    schedule 29.08.2017


Ответы (1)


path.toAbsolutePath().normalize() действительно добился цели.

Предположим, у нас есть символическая ссылка /var/spool/mail, указывающая на /var/mail:

final Path path = Paths.get("/var/./spool/../spool//mail/./");
System.out.println(path.toAbsolutePath().normalize());
System.out.println(path.toRealPath(NOFOLLOW_LINKS));

В приведенном выше примере в обоих случаях канонический путь печатается с символическими ссылками, оставленными неразрешенными:

/var/spool/mail
/var/spool/mail
person Bass    schedule 25.10.2018