Difference between getCanonicalPath and toRealPath

Are there cases where File.getCanonicalPath () and File.toPath (). will toRealPath () give different results? They seem to do both, but the documentation never states that they should do the same. Are there borderline cases where I prefer one method over another? What about File.getAbsolutePath () and Path.toAbsolutePath () - should they work the same?

+5
source share
5 answers

Conclusions:

  • getAboslutePath and getPath never getPath error, because they do not check
  • getCanonicalPath achieves invalid results when the drive letter from getCanonicalPath or differs from the current folder
  • toPath().toRealPath() validates, but the file must exist and may or may not follow symbolic links
  • toPath() is safe enough and does not require the file to exist.
  • .toPath().toAbsolutePath().normalize() is the best .toPath().toAbsolutePath().normalize() without the need for a file

I did a similar @John test on Windows

  @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(""); } 

Results:

 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) 
+1
source

The canonical path is absolute and unique , but will have different meanings for different systems.

The canonical path is absolute and unique. The exact definition of the canonical form depends on the system.

The real path is the actual path in relation to the system. You will also need to go through, regardless of whether you are dealing with symbolic links, where it is implicitly processed using canonicalPath .

The exact definition of this method depends on the implementation, but in general it follows from this path, an absolute path that finds the same file as this path, but with name elements that represent the actual directory and file name. For example, where file name matching in the file system is case insensitive , then name elements represent the names in their actual case. In addition, the resulting path contains redundant name elements.

So, these two methods can return different things, but it really depends on your system. If you need something unique, then canonicalPath is your safest bet, even if it's not Path .

+3
source

Of course, the example below shows some differences. Also getCanonicalPath will throw an exception if the file does not exist.

getCanonicalPath returns the path in its canonical or simplest form (from http://www.merriam-webster.com/dictionary/canonical%20form )

 import java.io.File; public class FileExample { public static void main(String[] args) throws Exception { File file = new File("/TEMP/../TEMP/myfile.txt"); System.out.println("ABS: " + file.getAbsolutePath()); System.out.println(" TO: " + file.toPath()); System.out.println("GET: " + file.getPath()); System.out.println("CAN: " + file.getCanonicalPath()); } } ABS: C:\TEMP\..\TEMP\myfile.txt TO: \TEMP\..\TEMP\myfile.txt GET: \TEMP\..\TEMP\myfile.txt CAN: C:\TEMP\myfile.txt 
+2
source

From my tests, I noticed that

  • Path.toRealPath () will throw java.nio.file.NoSuchFileException if the file does not exist (Javadoc: returns the real path to the file existing .)

  • File.getCanonicalPath () will not throw an exception if the file does not exist (it will only throw an IOException if the file name itself is invalid and contains '\ 0' char in it.

Thus, the first is not suitable if you want to use it to check the path to the actual creation of the file.

You are correct that the Javadoc for both methods is somewhat shallow.

+1
source

The API states that the canonical path usually removes redundancy and allows symbolic links, etc.

Try the following on a UNIX machine:

 File file = new File("../test.txt"); // execute from /tmp/java/example file.getAbsolutePath(); // evaluates to /tmp/java/example/../test.txt file.getCanonicalPath(); // evaluates to /tmp/java/test.txt 

The difference between File and Path is that Path is part of the new NIO API, which has many improvements and is more flexible.

As an example, you could exchange the file system implementation with NIO (see https://github.com/google/jimfs ), while java.io.File forces you can work with the file system of your host.

0
source

All Articles