Comment Java résout-il un chemin relatif dans new File()?

J'essaie de comprendre la façon dont Java résout le chemin relatif lors de la création d'un objet File.

Système d'exploitation utilisé: Windows

Pour l'extrait ci-dessous, je reçois un IOException car il ne peut pas trouver le chemin:

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

Ma compréhension ici est que Java traite le chemin fourni comme absolu et renvoie une erreur lorsque le chemin n'existe pas. Donc, c'est logique.

Lorsque je mets à jour le code ci-dessus pour utiliser le chemin relatif:

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

, Il crée un nouveau fichier et fournit la sortie ci-dessous:

test..test.txt
C:JavaForTesterstest..test.txt
C:JavaForTesterstest.txt

Dans ce cas, mon hypothèse est, même si le chemin fourni n'existe pas, parce que le chemin contient "/../", java traite cela comme un chemin relatif et crée le fichier dans le user.dir. Donc, cela a aussi du sens.

Mais si je mets à jour le chemin relatif comme ci-dessous:

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

Ensuite, je reçois IOException: L'accès est refusé.

, Mes questions sont:

  1. pourquoi "test/../test.txt" est traité comme un chemin relatif et crée le fichier dans "user.dir" mais "test/../../test.txt" renvoie une erreur? Où tente-t-il de créer le fichier pour le chemin "test/../../test.txt"?
  2. Lorsque le chemin relatif spécifié n'est pas trouvé, le fichier semble être créé dans le user.dir. Donc, il me semble que les deux scénarios ci-dessous font la même chose:

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

Y a-t-il donc un cas réel où l'on utiliserait le scénario 1 au lieu du scénario 2?

Je suppose que je manque quelque chose d'évident ici ou que j'ai fondamentalement mal compris les chemins relatifs. J'ai parcouru les documents Java pour le fichier et je ne suis pas en mesure de trouver une explication à cela. Il y a quelques questions postées dans Stack Overflow concernant les chemins relatifs, mais celles que j'ai consultées concernaient des scénarios spécifiques et pas exactement la façon dont les chemins relatifs sont résolus.

Ce sera génial si quelqu'un pouvait m'expliquer comment cela fonctionne ou pointer vers des liens connexes?

33
demandé sur Andrew Thompson 2014-01-11 14:08:01

6 réponses

Il y a une notion de working directory.
Ce répertoire est représenté par un . (point).
Dans les chemins relatifs, tout le reste est relatif.

Mettez simplement le . (le répertoire de travail) est l'endroit où vous exécutez votre programme.
Dans certains cas, le répertoire de travail peut être changé, mais en général c'est
ce point représente. Je pense que c'est C:\JavaForTesters\ dans votre cas.

, Donc test\..\test.txt signifie: le sous-répertoire test
dans mon répertoire de travail, puis un niveau supérieur, puis le
fichier test.txt. C'est fondamentalement la même chose que juste test.txt.

Pour plus de détails, consultez ici.

Http://docs.oracle.com/javase/7/docs/api/java/io/File.html

Http://docs.oracle.com/javase/tutorial/essential/io/pathOps.html

17
répondu peter.petrov 2014-01-11 10:26:28

Lorsque votre chemin commence par une racine c'est à dire C:\ dans windows ou / dans Unix ou dans les ressources java chemin, il est considéré comme un chemin d'accès absolu. Tout le reste est relatif, donc

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")

La principale différence entre getAbsolutePath et getCanonicalPath est que le premier concatène un chemin parent et un chemin enfant, de sorte qu'il peut contenir des points: .. ou .. getCanonicalPath retourne toujours le même chemin pour un fichier particulier.

Remarque: File.equals utilise une forme abstraite d'un chemin d'accès (getAbsolutePath) pour comparer des fichiers, cela signifie donc que deux objets File pour le même peuvent ne pas être égaux et que File s ne sont pas sûrs à utiliser dans des collections comme Map ou Set.

9
répondu Andrey Chaschev 2017-12-15 17:29:24

Le répertoire de travail est un concept commun à pratiquement tous les systèmes d'exploitation et langages de programmes, etc. C'est le répertoire dans lequel votre programme s'exécute. C'est généralement (mais pas toujours, il existe des moyens pour changer le répertoire de l'application.

Les chemins relatifs sont ceux qui démarrent sans spécificateur de lecteur. Donc sous linux, ils ne commencent pas par un /, sous windows, ils ne commencent pas par un C:\, etc. Ceux-ci commencent toujours à partir de votre répertoire de travail.

Absolue les chemins sont ceux qui commencent par un spécificateur de lecteur (ou de machine pour les chemins réseau). Ils vont toujours dès le début de ce lecteur.

5
répondu Tim B 2014-01-11 10:18:50

Sous windows et Netbeans, vous pouvez définir le chemin relatif comme suit:

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

Sous Linux et Netbeans, vous pouvez définir le chemin relatif comme suit:

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

Si vous avez votre code à l'intérieur Source Packages Je ne sais pas si c'est la même chose pour eclipse ou autre IDE

0
répondu Ricard Molins 2017-05-12 10:42:03

Seulement légèrement liée à la question, mais essayez d'envelopper votre tête autour de celui-ci. Donc non intuitif:

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
répondu djangofan 2017-09-10 18:48:32

Les chemins relatifs peuvent être mieux compris si vous savez comment Java exécute le programme.

Il existe un concept de répertoire de travail lors de l'exécution de programmes en Java. En supposant que vous avez une classe, disons, FileHelper qui fait l'IO sous /User/home/Desktop/projectRoot/src/topLevelPackage/.

Selon le cas où vous invoquez java pour exécuter le programme, vous aurez un répertoire de travail différent. Si vous exécutez votre programme à partir de l'intérieur et IDE, il sera très probablement projectRoot.

  • Dans ce cas, $ projectRoot/src : java topLevelPackage.FileHelper, il sera src.

  • Dans ce cas, $ projectRoot : java -cp src topLevelPackage.FileHelper c'est projectRoot.

  • Dans ce cas, $ /User/home/Desktop : java -cp ./projectRoot/src topLevelPackage.FileHelper c'est Desktop.

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

Ainsi, votre racine de chemin relatif (.) se résout dans votre répertoire de travail. Ainsi, pour être mieux sûr de l'endroit où écrire des fichiers, il est dit de considérer l'approche ci-dessous.

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);

    }
}

J'espère que cela aide.

0
répondu Ravi Tiwari 2018-05-22 16:55:58