web-dev-qa-db-fra.com

Comment Java résout-il un chemin relatif dans un nouveau fichier ()?

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

OS utilisé: Windows

Pour l'extrait ci-dessous, je reçois une IOException car il ne trouve pas 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();
        }
}

D'après ce que j'ai compris, Java traite le chemin fourni comme absolu et renvoie une erreur lorsqu'il n'existe pas. C'est donc logique.

Quand 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:\JavaForTesters\test\..\test.txt
C:\JavaForTesters\test.txt

Dans ce cas, mon hypothèse est que, même si le chemin fourni n'existe pas, car il contient "/../", Java le traite comme un chemin relatif et crée le fichier dans le user.dir. Cela a donc également un 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, j'obtiens 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 avoir été 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();
    

Existe-t-il donc un cas concret dans lequel 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 des chemins relatifs fondamentalement mal compris. J'ai parcouru les documents Java pour File et je ne suis pas en mesure de trouver une explication à cela. Stack Overflow contient pas mal de questions sur les chemins relatifs, mais celles que j'ai consultées portaient sur des scénarios spécifiques et non sur la façon dont les chemins relatifs sont résolus. 

Ce serait formidable si quelqu'un pouvait m'expliquer comment cela fonctionne ou indiquer des liens connexes?

36
Eswar

Il existe un concept de working directory.
Ce répertoire est représenté par un . (point).
Dans les chemins relatifs, tout le reste lui est relatif.

Il suffit de placer le . (le répertoire de travail) où vous exécutez votre programme. 
Dans certains cas, le répertoire de travail peut être modifié, mais en général 
ce que le 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 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

20
peter.petrov

Lorsque votre chemin commence par un répertoire racine, à savoir C:\ dans Windows ou / dans Unix ou dans le chemin des ressources Java, il est considéré comme un chemin 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 retournera toujours le même chemin pour un fichier particulier.

Remarque: File.equals utilise une forme abstraite de chemin (getAbsolutePath) pour comparer des fichiers. Cela signifie donc que deux objets File de même peuvent ne pas être égaux et que Files est dangereux à utiliser dans des collections comme Map ou Set.

9
Andrey Chaschev

Le répertoire de travail est un concept commun à presque tous les systèmes d'exploitation et à toutes les langues de programme, etc. C'est le répertoire dans lequel votre programme est exécuté. C’est généralement (mais pas toujours, il existe des moyens de le changer) le répertoire dans lequel se trouve l’application.

Les chemins relatifs sont ceux qui commencent sans spécificateur de lecteur. Donc, sous Linux, ils ne commencent pas par un /, dans Windows, ils ne commencent pas par un C:\, etc. Ils partent toujours de votre répertoire de travail.

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

5
Tim B

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 dans Source Packages.__, je ne sais pas s'il en va de même pour Eclipse ou autre

1
Ricard Molins

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 le IO sous /User/home/Desktop/projectRoot/src/topLevelPackage/

Selon le cas où vous appelez Java pour exécuter le programme, vous aurez un répertoire de travail différent. Si vous exécutez votre programme de l'intérieur et de l'EDI, il s'agira probablement de projectRoot.

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

  • Dans ce cas, $ projectRoot : Java -cp src topLevelPackage.FileHelper sera projectRoot.

  • Dans ce cas, $ /User/home/Desktop : Java -cp ./projectRoot/src topLevelPackage.FileHelper sera Desktop.

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

Ainsi, votre chemin relatif racine (.) est résolu dans votre répertoire de travail. Ainsi, pour être plus sûr de l'endroit où écrire les fichiers, on considère qu'il faut 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 t'aides.

1
Ravi Tiwari

Légèrement lié à la question, mais essayez de vous en tenir à celle-ci. Donc, pas 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
djangofan