Was ist der Unterschied zwischen getPath (), getAbsolutePath () und getCanonicalPath () in Java?

583

Was ist der Unterschied zwischen getPath(), getAbsolutePath()und getCanonicalPath()in Java?

Und wann benutze ich jeden?

knt
quelle
Vergessen Sie nicht, Path.toAbsolutePath().normalize()was ein guter Mittelweg zwischen kanonischem (realem) Pfad und absolutem Pfad allein ist.
eckes

Antworten:

625

Betrachten Sie diese Dateinamen:

C:\temp\file.txt - Dies ist ein Pfad, ein absoluter Pfad und ein kanonischer Pfad.

.\file.txt- Dies ist ein Weg. Es ist weder ein absoluter noch ein kanonischer Weg.

C:\temp\myapp\bin\..\\..\file.txt- Dies ist ein Pfad und ein absoluter Pfad. Es ist kein kanonischer Weg.

Ein kanonischer Pfad ist immer ein absoluter Pfad.

Das Konvertieren von einem Pfad in einen kanonischen Pfad macht ihn absolut (normalerweise wird das aktuelle Arbeitsverzeichnis angeheftet, z . B. ./file.txtwird es c:/temp/file.txt). Der kanonische Pfad einer Datei "bereinigt" lediglich den Pfad, indem ..\Dinge wie Symlinks (unter Unixen) entfernt und aufgelöst werden .

Beachten Sie auch das folgende Beispiel mit 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());

Während sich beide Pfade auf denselben Speicherort beziehen, ist die Ausgabe sehr unterschiedlich:

C:\Windows
C:\Windows\System32\drivers
nr
quelle
11
FWIW, es ist keine Selbstverständlichkeit, dass C:\temp\file.txtes sich um einen kanonischen Pfad handelt. Das temporäre Verzeichnis kann ein Softlink oder ein Hardlink des Dateisystems (eine Verbindung in NTFS) sein, und file.txt kann ein Softlink sein. Ich weiß nicht, ob Dateisysteme Hardlinks zu Dateien unterscheiden können.
Lawrence Dol
1
path berücksichtigt diese Probleme oder das Vorhandensein einer der Komponenten nicht wirklich, sondern nur die Syntax.
Flucht-llc
Der kanonische Pfad (im Gegensatz zum normalisierten Pfad) trifft das Dateisystem.
Eckes
1
Grundsätzlich kann ich keinen Grund sehen , warum man verwenden sollte getAbsolutePath()statt getCanonicalPath(). Es sieht sogar besser aus, weil der Kanonische diese ../Teile automatisch auflöst .
Scadge
Vergessen Sie nicht, dass getCanonicalPathWürfe eine IOExceptionWeile getAbsolutePathnicht werfen , wenn dies eine Überlegung ist.
Verlassener Wagen
129

Der beste Weg, ein Gefühl für solche Dinge zu bekommen, ist, sie auszuprobieren:

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) {}
    }
}

Ihre Ausgabe wird ungefähr so ​​aussehen:

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

Also, getPath()haben Sie den Pfad basierend auf dem File - Objekt, das nicht relativ sein kann oder nicht; getAbsolutePath()gibt Ihnen einen absoluten Pfad zur Datei; und getCanonicalPath()gibt Ihnen den eindeutigen absoluten Pfad zur Datei. Beachten Sie, dass es eine große Anzahl absoluter Pfade gibt, die auf dieselbe Datei verweisen, aber nur einen kanonischen Pfad.

Wann sollte jeder verwendet werden? Hängt davon ab, was Sie erreichen möchten. Wenn Sie jedoch versuchen möchten, festzustellen, ob zwei Filesauf dieselbe Datei auf der Festplatte zeigen, können Sie ihre kanonischen Pfade vergleichen. Nur ein Beispiel.

dave4351
quelle
7
Es ist fraglich, ob Java die Implementierung eines "absoluten" Pfades falsch verstanden hat. Es hätte wirklich alle relativen Pfadelemente in einem absoluten Pfad entfernen sollen. Die kanonische Form würde dann alle FS-Links oder -Verbindungen im Pfad entfernen.
Lawrence Dol
but if you were trying to see if two Files are pointing at the same file on diskWie? Beispiel bitte?
Asif Mushtaq
@UnKnown: Dafür würden Sie den kanonischen Pfad verwenden.
Lawrence Dol
67

Zusamenfassend:

  • getPath()Ruft die Pfadzeichenfolge ab, mit der das FileObjekt erstellt wurde, und es kann sich um ein relativ aktuelles Verzeichnis handeln.
  • getAbsolutePath() Ruft die Pfadzeichenfolge ab, nachdem sie im aktuellen Verzeichnis aufgelöst wurde, wenn sie relativ ist, was zu einem vollständig qualifizierten Pfad führt.
  • getCanonicalPath()Ruft die Pfadzeichenfolge ab, nachdem ein relativer Pfad für das aktuelle Verzeichnis aufgelöst wurde, und entfernt alle relativen Pfade ( .und ..) sowie alle Dateisystemverknüpfungen, um einen Pfad zurückzugeben, den das Dateisystem als kanonisches Mittel betrachtet, um auf das Dateisystemobjekt zu verweisen, auf das es verweist.

Außerdem verfügt jede dieser Dateien über ein Dateiäquivalent, das das entsprechende FileObjekt zurückgibt .

Lawrence Dol
quelle
36

getPath()Gibt den Pfad zurück, der zum Erstellen des FileObjekts verwendet wurde. Dieser Rückgabewert wird nicht basierend auf dem Speicherort geändert (die folgenden Ergebnisse gelten für Fenster, Trennzeichen unterscheiden sich offensichtlich an anderer Stelle).

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()Löst den Pfad basierend auf dem Ausführungsort oder dem Laufwerk auf. Also wenn laufen von 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()ist systemabhängig. Dadurch wird der eindeutige Speicherort aufgelöst, den der Pfad darstellt. Wenn Sie also "." Im Pfad haben, werden diese normalerweise entfernt.

Wann man sie benutzt. Es hängt davon ab, was Sie erreichen wollen. getPath()ist nützlich für die Portabilität. getAbsolutePath()ist nützlich, um den Speicherort des Dateisystems zu finden, und getCanonicalPath()ist besonders nützlich, um zu überprüfen, ob zwei Dateien identisch sind.

Reicher Verkäufer
quelle
Kannst du mir ein Beispiel dafür geben? getCanonicalPath() is particularly useful to check if two files are the same.
Asif Mushtaq
20

Das Wichtigste ist, dass die FileKlasse versucht, eine Ansicht dessen darzustellen, was Sun gerne als "hierarchische Pfadnamen" bezeichnet (im Grunde ein Pfad wie c:/foo.txtoder /usr/muggins). Aus diesem Grund erstellen Sie Dateien in Form von Pfaden. Die Operationen, die Sie beschreiben, sind alle Operationen auf diesen "Pfadnamen".

  • getPath()Ruft den Pfad ab, mit dem die Datei erstellt wurde ( ../foo.txt)
  • getAbsolutePath()Ruft den Pfad ab, mit dem die Datei erstellt wurde, enthält jedoch Informationen zum aktuellen Verzeichnis, wenn der Pfad relativ ist ( /usr/bobstuff/../foo.txt)
  • getCanonicalPath() versucht , eine eindeutige Darstellung des absoluten Pfads zur Datei abzurufen. Dies eliminiert die Indirektion von ".." und "." Referenzen ( /usr/foo.txt).

Hinweis Ich sage Versuche - beim Bilden eines kanonischen Pfades kann die VM einen werfen IOException. Dies tritt normalerweise auf, weil einige Dateisystemoperationen ausgeführt werden, von denen jede fehlschlagen kann.

Butterhuhn
quelle
3

Ich finde, ich muss selten verwenden, getCanonicalPath()aber wenn eine Datei mit einem Dateinamen im DOS 8.3-Format unter Windows angegeben wird, wie z. B. die java.io.tmpdirRückgabe der Systemeigenschaft, gibt diese Methode den "vollständigen" Dateinamen zurück.

Matthew Wise
quelle