it-swarm.com.de

Wie löst Java einen relativen Pfad in der neuen Datei () auf?

Ich versuche zu verstehen, wie Java den relativen Pfad beim Erstellen eines File-Objekts auflöst.

Verwendetes Betriebssystem: Windows

Für den folgenden Ausschnitt bekomme ich eine IOException, da sie den Pfad nicht finden kann:

@Test
public void testPathConversion() {
        File f = new File("test/test.txt");
        try {
            f.createNewFile();
            System.out.println(f.getPath());
            System.out.println(f.getAbsolutePath());    
            System.out.println(f.getCanonicalPath());
        } catch (Exception e) {
            e.printStackTrace();
        }
}

Mein Verständnis hier ist, Java behandelt den angegebenen Pfad als absolut und gibt einen Fehler zurück, wenn der Pfad nicht vorhanden ist. Also macht es Sinn.

Wenn ich den obigen Code zur Verwendung des relativen Pfads aktualisiere: 

@Test
    public void testPathConversion() {
        File f = new File("test/../test.txt");
        try {
            f.createNewFile();
            System.out.println(f.getPath());
            System.out.println(f.getAbsolutePath());    
            System.out.println(f.getCanonicalPath());
        } catch (Exception e) {
            e.printStackTrace();
        }    
    }

Es erstellt eine neue Datei und stellt die folgende Ausgabe bereit:

test\..\test.txt
C:\JavaForTesters\test\..\test.txt
C:\JavaForTesters\test.txt

In diesem Fall gehe ich davon aus, dass der Pfad zwar nicht existiert, da der Pfad "/../" enthält. Java behandelt dies jedoch als relativen Pfad und erstellt die Datei im user.dir. Das macht also auch Sinn.

Aber wenn ich den relativen Pfad wie folgt aktualisiere:

   @Test
    public void testPathConversion() {
        File f = new File("test/../../test.txt");
        try {
            f.createNewFile();
            System.out.println(f.getPath());
            System.out.println(f.getAbsolutePath());
            System.out.println(f.getCanonicalPath());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Dann bekomme ich IOException: Zugriff wird verweigert.

Meine Fragen sind:

  1. warum wird "test/../test.txt" als relativer Pfad behandelt und die Datei in "user.dir" erstellt, aber "test/../../test.txt" gibt einen Fehler zurück? Wo wird versucht, die Datei für den Pfad "test/../../test.txt" zu erstellen?
  2. Wenn der angegebene relative Pfad nicht gefunden wird, scheint die Datei in user.dir erstellt zu sein. Es scheint mir so, dass die folgenden zwei Szenarien dasselbe tun:

    //scenario 1
    File f = new File("test/../test.txt");
    f.createNewFile();
    
    //scenario 2
    File f = new File("test.txt");
    f.createNewFile();
    

Gibt es also einen Fall aus der realen Welt, in dem Szenario 1 anstelle von Szenario 2 verwendet würde? 

Ich vermute, dass ich hier etwas Offensichtliches vermisse oder die relativen Pfade grundlegend missverstanden habe. Ich habe die Java-Dokumente für File durchgesehen und kann dafür keine Erklärung finden. In Stack Overflow gibt es einige Fragen zu relativen Pfaden, aber die, die ich nachgeschlagen habe, betrafen bestimmte Szenarien und nicht genau, wie relative Pfade aufgelöst werden. 

Es wäre toll, wenn mir jemand erklären könnte, wie das funktioniert, oder auf verwandte Links verweisen.

36
Eswar

Es gibt ein Konzept eines working directory.
Dieses Verzeichnis wird durch einen . (Punkt) dargestellt.
In relativen Pfaden ist alles andere relativ.

Fügen Sie einfach das . (das Arbeitsverzeichnis) an dem Sie Ihr Programm ausführen. 
.__ Das Arbeitsverzeichnis kann in einigen Fällen geändert werden, dies ist jedoch im Allgemeinen der Fall 
was der Punkt darstellt. Ich denke, das ist in Ihrem Fall C:\JavaForTesters\.

test\..\test.txt bedeutet also: das Unterverzeichnis test 
in meinem Arbeitsverzeichnis, dann eine Ebene nach oben, dann die 
datei test.txt. Dies ist im Grunde dasselbe wie nur test.txt.

Weitere Details finden Sie hier.

http://docs.Oracle.com/javase/7/docs/api/Java/io/File.html

http://docs.Oracle.com/javase/tutorial/essential/io/pathOps.html

20
peter.petrov

Wenn Ihr Pfad mit einem Root-Verzeichnis beginnt, d. H. C:\ in Windows oder / in Unix oder in Java-Ressourcenpfad, wird er als absoluter Pfad betrachtet. Alles andere ist relativ 

new File("test.txt") is the same as new File("./test.txt")

new File("test/../test.txt") is the same as new File("./test/../test.txt")

Der Hauptunterschied zwischen getAbsolutePath und getCanonicalPath besteht darin, dass der erste Pfad einen übergeordneten und einen untergeordneten Pfad verkettet, sodass er Punkte enthalten kann: .. oder .. getCanonicalPath gibt immer den gleichen Pfad für eine bestimmte Datei zurück.

Hinweis: File.equals verwendet eine abstrakte Form eines Pfads (getAbsolutePath), um Dateien zu vergleichen. Dies bedeutet, dass zwei File-Objekte für denselben möglicherweise nicht gleich sind und Files in Sammlungen wie Map oder Set nicht sicher zu verwenden sind.

9
Andrey Chaschev

Das Arbeitsverzeichnis ist ein allgemeines Konzept für praktisch alle Betriebssysteme und Programmiersprachen usw. Es ist das Verzeichnis, in dem Ihr Programm ausgeführt wird. Dies ist normalerweise (aber nicht immer, es gibt Möglichkeiten, es zu ändern) das Verzeichnis, in dem sich die Anwendung befindet.

Relative Pfade sind diejenigen, die ohne Laufwerksangabe beginnen. In Linux beginnen sie also nicht mit einem /, in Windows beginnen sie nicht mit einem C:\, usw.

Absolute Pfade sind diejenigen, die mit einem Laufwerk (oder einer Maschine für Netzwerkpfade) beginnen. Sie gehen immer vom Anfang dieser Fahrt.

5
Tim B

Unter Windows und Netbeans können Sie den relativen Pfad folgendermaßen einstellen:

    new FileReader("src\\PACKAGE_NAME\\FILENAME");

Unter Linux und Netbeans können Sie den relativen Pfad folgendermaßen einstellen:

    new FileReader("src/PACKAGE_NAME/FILENAME");

Wenn Sie Ihren Code in Source Packages.__ haben, weiß ich nicht, ob er für Eclipse oder andere IDE gleich ist

1
Ricard Molins

Relative Pfade können am besten verstanden werden, wenn Sie wissen, wie Java das Programm ausführt. 

Beim Ausführen von Programmen in Java gibt es ein Konzept des Arbeitsverzeichnisses. Angenommen, Sie haben eine Klasse, sagen wir FileHelper, die IO unter /User/home/Desktop/projectRoot/src/topLevelPackage/

Abhängig von dem Fall, in dem Sie Java aufrufen, um das Programm auszuführen, haben Sie ein anderes Arbeitsverzeichnis. Wenn Sie Ihr Programm in IDE und IDE ausführen, wird es höchstwahrscheinlich projectRoot sein.

  • In diesem Fall ist $ projectRoot/src : Java topLevelPackage.FileHelpersrc.

  • In diesem Fall ist $ projectRoot : Java -cp src topLevelPackage.FileHelperprojectRoot.

  • In diesem Fall ist $ /User/home/Desktop : Java -cp ./projectRoot/src topLevelPackage.FileHelperDesktop.

(Assuming $ is your command Prompt with standard Unix-like FileSystem. Similar correspondence/parallels with Windows system)

Ihr relativer Pfad root (.) wird also in Ihr Arbeitsverzeichnis aufgelöst. Um besser wissen zu können, wo Dateien geschrieben werden sollen, sollte der folgende Ansatz berücksichtigt werden.

package topLevelPackage

import Java.io.File;
import Java.nio.file.Path;
import Java.nio.file.Paths;

public class FileHelper {

    // Not full implementation, just barebone stub for path
    public void createLocalFile() {

        // Explicitly get hold of working directory
        String workingDir = System.getProperty("user.dir");

        Path filePath = Paths.get(workingDir+File.separator+"sampleFile.txt");

        // In case we need specific path, traverse that path, rather using . or .. 
        Path pathToProjectRoot = Paths.get(System.getProperty("user.home"), "Desktop", "projectRoot");

        System.out.println(filePath);
        System.out.println(pathToProjectRoot);

    }
}

Hoffe das hilft.

1
Ravi Tiwari

Nur ein wenig mit der Frage verbunden, aber versuchen Sie, Ihren Kopf um diese zu wickeln. So intuitiv:

import Java.nio.file.*;
class Main {
  public static void main(String[] args) {
    Path p1 = Paths.get("/personal/./photos/./readme.txt");
    Path p2 = Paths.get("/personal/index.html");
    Path p3 = p1.relativize(p2);
    System.out.println(p3); //prints  ../../../../index.html  !!
  }
}
0
djangofan