В чем разница между getPath (), getAbsolutePath () и getCanonicalPath () в Java?


583

В чем разница между getPath(), getAbsolutePath()и getCanonicalPath()в Java?

И когда я использую каждый?


Не забывайте, Path.toAbsolutePath().normalize()что это хорошая середина между каноническим (реальным) путем и только абсолютным путем.
eckes

Ответы:


625

Рассмотрим эти имена файлов:

C:\temp\file.txt - Это путь, абсолютный путь и канонический путь.

.\file.txt- Это путь. Это не абсолютный и не канонический путь.

C:\temp\myapp\bin\..\\..\file.txt- Это путь и абсолютный путь. Это не канонический путь.

Канонический путь - это всегда абсолютный путь.

Преобразование из пути в канонический путь делает его абсолютным (обычно это привязка к текущему рабочему каталогу, например, ./file.txtстановится c:/temp/file.txt). Канонический путь к файлу просто «очищает» путь, удаляя и разрешая такие вещи, как ..\и разрешая символические ссылки (в unixes).

Также обратите внимание на следующий пример с nio.Paths:

String canonical_path_string = "C:\\Windows\\System32\\";
String absolute_path_string = "C:\\Windows\\System32\\drivers\\..\\";

System.out.println(Paths.get(canonical_path_string).getParent());
System.out.println(Paths.get(absolute_path_string).getParent());

Хотя оба пути относятся к одному и тому же местоположению, выходные данные будут совершенно разными:

C:\Windows
C:\Windows\System32\drivers

11
FWIW, это не дано, C:\temp\file.txtэто канонический путь - временный каталог может быть мягкой ссылкой файловой системы или жесткой ссылкой (соединение в NTFS), а file.txt может быть мягкой ссылкой. Я не знаю, могут ли файловые системы различать жесткие ссылки на файлы.
Лоуренс Дол

1
На самом деле путь не учитывает эти проблемы или существование каких-либо компонентов, а только его синтаксис.
побег-ООО

Это так, канонический путь (в отличие от нормализованного пути) попадает в файловую систему.
eckes

1
В принципе, я не вижу причины, по которой следует использовать getAbsolutePath()вместо getCanonicalPath(). Это даже выглядит лучше, потому что канонический автоматически разрешает эти ../части.
Scadge

Не забывайте, что getCanonicalPathбросает какое- IOExceptionто время getAbsolutePathнет, если это соображение.
заброшенная корзина

129

Лучший способ почувствовать такие вещи - попробовать их:

import java.io.File;
public class PathTesting {
    public static void main(String [] args) {
        File f = new File("test/.././file.txt");
        System.out.println(f.getPath());
        System.out.println(f.getAbsolutePath());
        try {
            System.out.println(f.getCanonicalPath());
        }
        catch(Exception e) {}
    }
}

Ваш вывод будет примерно таким:

test\..\.\file.txt
C:\projects\sandbox\trunk\test\..\.\file.txt
C:\projects\sandbox\trunk\file.txt

Итак, getPath()дает вам путь, основанный на объекте File, который может быть или не быть относительным; getAbsolutePath()дает вам абсолютный путь к файлу; и getCanonicalPath()дает вам уникальный абсолютный путь к файлу. Обратите внимание, что существует огромное количество абсолютных путей, которые указывают на один и тот же файл, но только один канонический путь.

Когда использовать каждый? Зависит от того, что вы пытаетесь выполнить, но если вы пытаетесь увидеть Files, указывают ли два файла на один и тот же файл на диске, вы можете сравнить их канонические пути. Всего один пример.


7
Можно утверждать, что Java неправильно реализовала «абсолютный» путь; он действительно должен был удалить все элементы относительного пути в абсолютном пути. Каноническая форма будет тогда удалять любые ссылки FS или соединения в пути.
Лоуренс Дол

but if you were trying to see if two Files are pointing at the same file on diskКак? пример пожалуйста?
Асиф Муштак

@UnKnown: вы бы использовали для этого канонический путь.
Лоуренс Дол

67

Короче говоря:

  • getPath()получает строку пути, с которой Fileбыл построен объект, и это может быть относительный текущий каталог.
  • getAbsolutePath() получает строку пути после разрешения ее относительно текущего каталога, если он относительный, в результате чего получается полный путь.
  • getCanonicalPath()получает строку пути после разрешения любого относительного пути к текущему каталогу и удаляет все относительные пути ( .и ..) и любые ссылки файловой системы, чтобы вернуть путь, который файловая система считает каноническим средством для ссылки на объект файловой системы, на который она указывает.

Кроме того, каждый из них имеет файловый эквивалент, который возвращает соответствующий Fileобъект.


36

getPath()возвращает путь, использованный для создания Fileобъекта. Это возвращаемое значение не изменяется в зависимости от местоположения, в котором оно выполняется (результаты ниже для окон, разделители, очевидно, отличаются в других местах)

File f1 = new File("/some/path");
String path = f1.getPath(); // will return "\some\path"

File dir = new File("/basedir");
File f2 = new File(dir, "/some/path");
path = f2.getPath(); // will return "\basedir\some\path"

File f3 = new File("./some/path");
path = f3.getPath(); // will return ".\some\path"

getAbsolutePath()разрешит путь в зависимости от места выполнения или диска. Так что если бежать из c:\test:

path = f1.getAbsolutePath(); // will return "c:\some\path"
path = f2.getAbsolutePath(); // will return "c:\basedir\some\path"
path = f3.getAbsolutePath(); // will return "c:\test\.\basedir\some\path"

getCanonicalPath()зависит от системы. Это разрешит уникальное местоположение, которое представляет путь. Так что если у вас есть какие-либо "." В пути, они обычно будут удалены.

Что касается того, когда их использовать. Это зависит от того, чего вы пытаетесь достичь. getPath()полезно для мобильности. getAbsolutePath()полезно, чтобы найти расположение файловой системы, и getCanonicalPath()особенно полезно, чтобы проверить, совпадают ли два файла.


Можете ли вы дать мне какой-нибудь пример этого? getCanonicalPath() is particularly useful to check if two files are the same.
Асиф Муштак

20

Главное, чтобы вы могли поразмыслить над тем, что Fileкласс пытается представить представление о том, что Sun любит называть «иерархическими путями» (в основном это путь, похожий на c:/foo.txtили /usr/muggins). Вот почему вы создаете файлы с точки зрения путей. Все операции, которые вы описываете, являются операциями с этим «путем».

  • getPath()извлекает путь, по которому был создан файл ( ../foo.txt)
  • getAbsolutePath()извлекает путь, с помощью которого был создан файл, но включает информацию о текущем каталоге, если путь относительный ( /usr/bobstuff/../foo.txt)
  • getCanonicalPath() пытается получить уникальное представление об абсолютном пути к файлу. Это устраняет косвенность от ".." и "." ссылки ( /usr/foo.txt).

Заметьте, я говорю попытки - при формировании канонического пути виртуальная машина может бросить IOException. Обычно это происходит потому, что он выполняет некоторые операции с файловой системой, любая из которых может дать сбой.


3

Я нахожу, что мне редко приходится использовать, getCanonicalPath()но, если в Windows указан файл с именем файла в формате DOS 8.3, например, java.io.tmpdirвозвращаемое свойство System, этот метод возвращает «полное» имя файла.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.