Canonical Path

0

What is Canonical path?

Canonical path is an absolute path and it is always unique. If the path is not absolute it converts into an absolute path and then cleans up the path by removing and resolving stuff like ., .., resolving symbolic links and converting drive letters to a standard case (on Microsoft Windows platforms). We will go through few examples to know what this means.

What is the difference between getCanonicalPath(), getAbsolutePath() and getPath()?

File Object also have other paths like getAbsolutePath() and getPath(). We will understand all three paths using an example. Below shows a directory path called C:/practise/test/demo.

C
|– practice
|    |– test
|    |    |– demo

First we will go through each method’s definition and then relate it with examples.
getPath() returns the path string that the File object was constructed with, and it may be relative or absolute path.
getAbsolutePath() returns the absolute path string. If the File Object is created based on a relative path then it will be resolved into a fully qualified path.

Whatever may be the path, getCanonicalPath() will always return a unique absolute path. Thus there is only one canonical path to a file, while there can be many absolute paths to a file (depending on the system).
Now some examples.

File file = new File(".");

getPath() returns the same path that is passed in =>.

getAbsolutePath() returns the absolute version of it =>C:\practise\.

Note that . is retained and the current directory is appended to it.
getCanonicalPath() returns the absolute path minus . =>C:\practise

Let’s see another example:

File file = new File("../practise/test/file/demo");

getPath() returns the same path that is passed in =>../practise/test/file/demo

getAbsolutePath() returns the absolute version of it =>C:/practise/../practise/test/file/demo. Note that .. is retained. The current directory is appended to it.

getCanonicalPath() returns the absolute path minus .. =>C:/practise/test/file/demo

In the below test case, there are three different versions of absolute path pointing to the same directory. The canonical version always returns the same unique path. If we want to assert whether two File Objects are equal, we will have to do it on their canonical versions.

public void testCanonicalPath() throws IOException {
        File path1 = new File("../practise/test/file/demo");
        File path2 = new File("c:/practise/../practise/./test/file/demo");
        File path3 = new File("c:/practise/test/file/demo");

        assertFalse(path1.equals(path2));
        assertFalse(path1.equals(path3));
        assertFalse(path1.getAbsoluteFile().equals(path2.getAbsoluteFile()));
        System.out.println("Absolute");
        System.out.println(path1.getAbsolutePath());
        System.out.println(path2.getAbsolutePath());
        System.out.println(path3.getAbsolutePath());

        System.out.println("Canonical");
        System.out.println(path1.getCanonicalPath());
        System.out.println(path2.getCanonicalPath());
        System.out.println(path3.getCanonicalPath());

        path1 = path1.getCanonicalFile();
        path2 = path2.getCanonicalFile();
        path3 = path3.getCanonicalFile();

        assertEquals(path1, path2);
        assertEquals(path1, path3);
    }

Output

Absolute
C:practise..practisetestfiledemo
c:practise..practise.testfiledemo
c:practisetestfiledemo

Canonical
C:practisetestfiledemo
C:practisetestfiledemo
C:practisetestfiledemo

Why do we need Canonical Path?

Imagine there is a system property which contains path to a string of directories and you are writing a framework that relies on this property to create a classloader. The property value will be set externally by the user. As a framework author, you need to make sure that all the directories are unique and discard the duplicated one. Here is where we need to get the canonical version of the files and add it to the set.

Share.

Leave A Reply