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:
- 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"
? -
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?
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
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
.
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.
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
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 !!
}
}
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 serasrc
.Dans ce cas,
$ projectRoot : java -cp src topLevelPackage.FileHelper
c'estprojectRoot
.Dans ce cas,
$ /User/home/Desktop : java -cp ./projectRoot/src topLevelPackage.FileHelper
c'estDesktop
.
(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.