getCanonicalPath 和 toRealPath 之间的区别

2022-09-04 20:07:56

是否存在 File.getCanonicalPath() 和 File.toPath().toRealPath() 会产生不同结果的情况?他们似乎做了两件非常相似的事情,但文档从未明确说明他们应该做同样的事情。在边界情况下,我是否更喜欢一种方法而不是另一种方法?File.getAbsolutePath() 与 Path.toAbsolutePath() 怎么样 - 它们应该以相同的方式工作吗?


答案 1

结论:

  • getAbsolutePath并且永远不会失败,因为他们不做验证getPath
  • getCanonicalPath当来自 url 的驱动器号无效或与当前文件夹不同时,达到无效结果
  • toPath().toRealPath() 正在检查有效性,但文件需要存在,也可以跟随或不遵循符号链接
  • toPath()足够安全,不需要文件存在。
  • .toPath().toAbsolutePath().normalize() 是最好的一个,不需要文件存在

我对windows中的@John进行了类似的测试

  @Test
  public void testCanonical() throws IOException {
    test("d:tarGet\\..\\Target", "File exist and drive letter is on the current one");
    test("d:tarGet\\..\\Target\\.\\..\\", "File exist and drive letter is on the current one, but parent of current drive should exist");
    test("d:tarGet\\non-existent\\..\\..\\Target\\.\\..\\", "Relative path contains non-existent file");
    test("d:target\\\\file", "Double slash");
    test("c:tarGet\\..\\Target\\.", "File doesn't exist and drive letter is on different drive than the current one");
    test("l:tarGet\\..\\Target\\.\\..\\", "Drive letter doesn't exist");
    test("za:tarGet\\..\\Target\\.\\..\\", "Drive letter is double so not valid");
    test("d:tarGet|Suffix", "Path contains invalid chars in windows (|)");
    test("d:tarGet\u0000Suffix", "Path contains invalid chars in both linux and windows (\\0)");
  }

  private void test(String filename, String message) throws IOException {
    java.io.File file = new java.io.File(filename);
    System.out.println("Use:  " + filename + " -> " + message);
    System.out.println("F-GET:     " + Try.of(() -> file.getPath()));
    System.out.println("F-ABS:     " + Try.of(() -> file.getAbsolutePath()));
    System.out.println("F-CAN:     " + Try.of(() -> file.getCanonicalPath()));
    System.out.println("P-TO:      " + Try.of(() -> file.toPath()));
    System.out.println("P-ABS:     " + Try.of(() -> file.toPath().toAbsolutePath()));
    System.out.println("P-NOR:     " + Try.of(() -> file.toPath().normalize()));
    System.out.println("P-NOR-ABS: " + Try.of(() -> file.toPath().normalize().toAbsolutePath()));
    System.out.println("P-ABS-NOR: " + Try.of(() -> file.toPath().toAbsolutePath().normalize()));
    System.out.println("P-REAL:    " + Try.of(() -> file.toPath().toRealPath()));
    System.out.println("");
  }

结果是:

Use:  d:tarGet\..\Target -> File exist and drive letter is on the current one
F-GET:     Success(d:tarGet\..\Target)
F-ABS:     Success(d:\home\raiser\work\restfs\tarGet\..\Target)
F-CAN:     Success(D:\home\raiser\work\restfs\target)
P-TO:      Success(d:tarGet\..\Target)
P-ABS:     Success(D:\home\raiser\work\restfs\tarGet\..\Target)
P-NOR:     Success(d:Target)
P-NOR-ABS: Success(D:\home\raiser\work\restfs\Target)
P-ABS-NOR: Success(D:\home\raiser\work\restfs\Target)
P-REAL:    Success(D:\home\raiser\work\restfs\target)

Use:  d:tarGet\..\Target\.\..\ -> File exist and drive letter is on the current one, but parent of current drive should exist
F-GET:     Success(d:tarGet\..\Target\.\..)
F-ABS:     Success(d:\home\raiser\work\restfs\tarGet\..\Target\.\..)
F-CAN:     Success(D:\home\raiser\work\restfs)
P-TO:      Success(d:tarGet\..\Target\.\..)
P-ABS:     Success(D:\home\raiser\work\restfs\tarGet\..\Target\.\..)
P-NOR:     Success(d:)
P-NOR-ABS: Success(D:\home\raiser\work\restfs\)
P-ABS-NOR: Success(D:\home\raiser\work\restfs)
P-REAL:    Success(D:\home\raiser\work\restfs)

Use:  d:tarGet\non-existent\..\..\Target\.\..\ -> Relative path contains non-existent file
F-GET:     Success(d:tarGet\non-existent\..\..\Target\.\..)
F-ABS:     Success(d:\home\raiser\work\restfs\tarGet\non-existent\..\..\Target\.\..)
F-CAN:     Success(D:\home\raiser\work\restfs)
P-TO:      Success(d:tarGet\non-existent\..\..\Target\.\..)
P-ABS:     Success(D:\home\raiser\work\restfs\tarGet\non-existent\..\..\Target\.\..)
P-NOR:     Success(d:)
P-NOR-ABS: Success(D:\home\raiser\work\restfs\)
P-ABS-NOR: Success(D:\home\raiser\work\restfs)
P-REAL:    Success(D:\home\raiser\work\restfs)

Use:  d:target\\file -> Double slash
F-GET:     Success(d:target\file)
F-ABS:     Success(d:\home\raiser\work\restfs\target\file)
F-CAN:     Success(D:\home\raiser\work\restfs\target\file)
P-TO:      Success(d:target\file)
P-ABS:     Success(D:\home\raiser\work\restfs\target\file)
P-NOR:     Success(d:target\file)
P-NOR-ABS: Success(D:\home\raiser\work\restfs\target\file)
P-ABS-NOR: Success(D:\home\raiser\work\restfs\target\file)
P-REAL:    Failure(java.nio.file.NoSuchFileException: D:\home\raiser\work\restfs\target\file)

Use:  c:tarGet\..\Target\. -> File doesn't exist and drive letter is on different drive than the current one
F-GET:     Success(c:tarGet\..\Target\.)
F-ABS:     Success(c:\\tarGet\..\Target\.)
F-CAN:     Success(C:\Target)
P-TO:      Success(c:tarGet\..\Target\.)
P-ABS:     Success(C:\tarGet\..\Target\.)
P-NOR:     Success(c:Target)
P-NOR-ABS: Success(C:\Target)
P-ABS-NOR: Success(C:\Target)
P-REAL:    Failure(java.nio.file.NoSuchFileException: C:\Target)

Use:  l:tarGet\..\Target\.\..\ -> Drive letter doesn't exist
F-GET:     Success(l:tarGet\..\Target\.\..)
F-ABS:     Success(l:\tarGet\..\Target\.\..)
F-CAN:     Success(L:\)
P-TO:      Success(l:tarGet\..\Target\.\..)
P-ABS:     Failure(java.io.IOError: java.io.IOException: Unable to get working directory of drive 'L')
P-NOR:     Success(l:)
P-NOR-ABS: Failure(java.io.IOError: java.io.IOException: Unable to get working directory of drive 'L')
P-ABS-NOR: Failure(java.io.IOError: java.io.IOException: Unable to get working directory of drive 'L')
P-REAL:    Failure(java.io.IOException: Unable to get working directory of drive 'L')

Use:  za:tarGet\..\Target\.\..\ -> Drive letter is double so not valid
F-GET:     Success(za:tarGet\..\Target\.\..)
F-ABS:     Success(D:\home\raiser\work\restfs\za:tarGet\..\Target\.\..)
F-CAN:     Success(D:\home\raiser\work\restfs)
P-TO:      Failure(java.nio.file.InvalidPathException: Illegal char <:> at index 2: za:tarGet\..\Target\.\..)
P-ABS:     Failure(java.nio.file.InvalidPathException: Illegal char <:> at index 2: za:tarGet\..\Target\.\..)
P-NOR:     Failure(java.nio.file.InvalidPathException: Illegal char <:> at index 2: za:tarGet\..\Target\.\..)
P-NOR-ABS: Failure(java.nio.file.InvalidPathException: Illegal char <:> at index 2: za:tarGet\..\Target\.\..)
P-ABS-NOR: Failure(java.nio.file.InvalidPathException: Illegal char <:> at index 2: za:tarGet\..\Target\.\..)
P-REAL:    Failure(java.nio.file.InvalidPathException: Illegal char <:> at index 2: za:tarGet\..\Target\.\..)

Use:  d:tarGet|Suffix -> Path contains invalid chars in windows (|)
F-GET:     Success(d:tarGet|Suffix)
F-ABS:     Success(d:\home\raiser\work\restfs\tarGet|Suffix)
F-CAN:     Failure(java.io.IOException: The filename, directory name, or volume label syntax is incorrect)
P-TO:      Failure(java.nio.file.InvalidPathException: Illegal char <|> at index 8: d:tarGet|Suffix)
P-ABS:     Failure(java.nio.file.InvalidPathException: Illegal char <|> at index 8: d:tarGet|Suffix)
P-NOR:     Failure(java.nio.file.InvalidPathException: Illegal char <|> at index 8: d:tarGet|Suffix)
P-NOR-ABS: Failure(java.nio.file.InvalidPathException: Illegal char <|> at index 8: d:tarGet|Suffix)
P-ABS-NOR: Failure(java.nio.file.InvalidPathException: Illegal char <|> at index 8: d:tarGet|Suffix)
P-REAL:    Failure(java.nio.file.InvalidPathException: Illegal char <|> at index 8: d:tarGet|Suffix)

答案 2

规范路径是绝对的和唯一的,但在不同的系统上具有不同的含义。

规范路径名既绝对又是唯一的。规范形式的精确定义是依赖于系统的。

实际路径是相对于系统的实际路径。无论您是否不处理符号链接,您还必须传入符号链接,其中它使用 隐式处理。canonicalPath

此方法的精确定义与实现相关,但通常它派生自此路径,此路径是定位与此路径相同的文件的绝对路径,但具有表示目录和文件的实际名称的 name 元素。例如,如果文件系统上的文件名比较不区分大小写,则 name 元素表示其实际大小写中的名称。此外,生成的路径删除了冗余的名称元素。

所以,是的,这两种方法可以返回不同的东西,但这实际上取决于您的系统。如果你需要一些独特的东西,那么这是你最安全的赌注,即使它不是.canonicalPathPath


推荐