web-dev-qa-db-fra.com

Java ne peut pas trouver de fichier lors de l'exécution via Eclipse

Lorsque j'exécute une application Java qui devrait lire à partir d'un fichier dans Eclipse, j'obtiens un Java.io.FileNotFoundException, même si le fichier se trouve dans le bon répertoire. Je peux très bien compiler et exécuter l'application à partir de la ligne de commande; le problème se produit uniquement dans Eclipse, avec plusieurs projets et applications. Existe-t-il un paramètre que je dois modifier dans les configurations d'exécution ou les chemins de génération pour qu'il trouve correctement le fichier?

21
derekerdmann

Le problème est probablement que votre application utilise un chemin d'accès relatif. Comme le dit @BalusC, les chemins d'accès relatifs peuvent être problématiques. Mais IMO, il va beaucoup trop loin quand il dit "[vous] ne devriez jamais utiliser des chemins relatifs dans les trucs Java.io".

Lorsqu'une application ouvre un fichier en utilisant (par exemple) le constructeur FileInputStream(File), les chemins d'accès relatifs sont résolus par rapport au "répertoire courant" dans un processus décrit comme suit dans le javadoc pour File.getAbsolutePath() .

[...] Sinon, ce chemin est résolu de manière dépendante du système. Sur les systèmes UNIX, un chemin d'accès relatif est rendu absolu en le résolvant par rapport au répertoire utilisateur actuel. Sur les systèmes Microsoft Windows, un chemin d'accès relatif est rendu absolu en le résolvant par rapport au répertoire actuel du lecteur nommé par le chemin d'accès, le cas échéant; sinon, il est résolu par rapport au répertoire utilisateur actuel.

Donc tout de suite, on voit que la notion de "répertoire courant" a des nuances différentes sur les plateformes Windows et UNIX. Le deuxième problème est qu'en pure Java vous ne pouvez pas trouver définitivement ce que le répertoire actuel est, et vous ne pouvez certainement pas le changer pour la JVM actuelle en utilisant Java pur. (Lorsque la JVM démarre, le " La propriété système user.dir "est définie sur le répertoire courant, mais rien n'empêche une application de modifier la propriété vous ne pouvez donc pas vous y fier entièrement. De plus, la modification de" user.dir "uniquement change la façon dont le chemin vide est résolu, pas les chemins relatifs en général.)

Alors, que devez-vous faire à ce sujet?

  • Une option consiste à utiliser des noms de chemin absolus pour faire référence aux fichiers. Ceci est fiable dans (presque) tous les cas, mais l'utilisation de noms de chemin absolus peut être problématique si l'utilisateur doit entrer le nom de chemin, ou si vous devez éviter les noms de chemin absolus câblés (ou configurés).

  • Une deuxième option consiste à utiliser les chemins d'accès relatifs aux chemins de classe et à localiser les fichiers relatifs au répertoire d'installation de l'application. Cela fonctionne si c'est ce que vous devez faire, mais présente un problème si vous devez passer un File à une méthode de bibliothèque. Cela n'aide pas non plus si vous essayez de trouver les préférences d'application de l'utilisateur. (En général, mettre les préférences utilisateur dans le répertoire d'installation est une erreur ...)

  • Une troisième option consiste à nommer un fichier par rapport à un répertoire absolu que vous obtenez ailleurs; par exemple. new File(System.getProperty("home.dir"), "foo/bar");.

  • La dernière option consiste à utiliser des chemins d'accès relatifs et à supposer que l'utilisateur sait ce que le répertoire actuel. Pour de nombreuses applications que l'utilisateur exécute à partir de la ligne de commande, c'est la bonne solution.

Dans le cas particulier d'Eclipse, il existe une solution simple. Accédez à la "configuration d'exécution" que vous utilisez pour lancer votre application, ouvrez l'onglet "Arguments" et cliquez sur le bouton radio "Autre". Entrez ensuite un nom de chemin absolu comme répertoire de travail pour l'application lancée. Lorsque la JVM enfant est lancée, elle aura le répertoire de travail spécifié comme répertoire actuel.

30
Stephen C

Une autre option consiste à déterminer simplement vers quel répertoire le "chemin actuel" pointe dans votre environnement - quel qu'il soit. Une fois que vous avez compris, vous pouvez choisir votre solution à partir de là. Il s'agit peut-être d'utiliser un chemin relatif approprié vers l'emplacement de votre fichier ou de déplacer le fichier.

    File testFile = new File("");
    String currentPath = testFile.getAbsolutePath();
    System.out.println("current path is: " + currentPath);
8
tgmoor

Lorsque vous créez une application par défaut Java dans Eclipse, vous obtenez cette structure de répertoire:

./Nom du projet/ - répertoire racine
./ProjectName/bin/ - répertoire de sortie, contenant les fichiers .class
./ProjectName/src/ - répertoire source, contenant les fichiers .Java

Si votre application demande "./data.txt", elle le recherchera par rapport au répertoire racine. Il s'agit du "répertoire de travail" et peut être configuré dans l'onglet arguments selon la réponse de Martin ci-dessus.

Vous dites que cela fonctionne à partir de la ligne de commande? Cela est probablement dû au fait que vous vous trouvez dans les dossiers bin ou src lorsque vous exécutez le binaire Java. Dans ce cas, le répertoire de travail est le répertoire dans lequel l'invite de commandes se trouve actuellement. Si, par exemple , vous allez dans le répertoire/src /, dites javac *.Java puis exécutez les fichiers à partir de là, il recherchera "./data.txt" dans le répertoire/src /. Si vous allez dans le répertoire/bin/et exécutez votre application à partir de là, il recherchera le fichier relatif au répertoire/bin /.

7
Gunslinger47

J'avais un problème similaire, j'ai placé mes fichiers dans un dossier nommé cobolcopybooks à l'intérieur du dossier src et j'ai essayé d'y accéder dans mon projet en utilisant classloader.getResource ("cobolcopybooks/demostud.cob") mais je recevais une exception de pointeur nul, je J'ai essayé plusieurs fois en nettoyant et en construisant les espaces de travail après plusieurs tentatives infructueuses. Je me suis rendu compte que je n'actualisais pas le projet pour permettre aux fichiers de se construire avec le projet. c'est-à-dire que ces fichiers doivent être visibles avec les autres fichiers de classe car au moment de l'exécution, le répertoire racine sera le répertoire bin et il y cherche ces fichiers.

2
Farheen Mohammad

Vous ne devez jamais utiliser des chemins relatifs dans Java.io. Le chemin dépendrait du répertoire de travail actuel, qui dépend de la façon dont vous avez démarré l'application et n'est donc pas en soi le même dans tous les environnements. Ceci est incontrôlable depuis l'intérieur de Java. Problème de portabilité! Utilisez toujours des chemins absolus. Ainsi, par exemple c:/path/to/file.ext Ou /path/to/file.ext (Avec la barre oblique principale) pour UNIX et consorts (ou même Windows lorsque la lettre de disque n'est pas pertinente).

Chaque fois que vous souhaitez envoyer des fichiers avec votre application, une pratique courante consiste également à les placer dans le chemin de classe . De cette façon, vous pouvez simplement utiliser ClassLoader#getResource() pour obtenir son emplacement. Il retourne un URL . Vous pouvez utiliser URL#toURI() ou URL#getPath() et le passer au constructeur de Java.io.File = et utilisez-le ensuite de la manière habituelle.

Dans votre projet Eclipse, le dossier src (où va votre source Java va) est essentiellement la racine du chemin de classe. De plus, il couvre également tous les autres projets et (externe) dossiers qui sont pris dans le projet Build Path.

En supposant que vous avez placé le fichier particulier dans le root du chemin de classe:

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL url = classLoader.getResource("file.ext");
File file = new File(url.getPath());
FileInputStream input = new FileInputStream(file);
// ...

Vous pouvez même utiliser ClassLoader#getResourceAsStream() pour obtenir directement un InputStream :

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream input = classLoader.getResourceAsStream("file.ext");
// ...

S'il est placé dans un package, vous pouvez simplement utiliser les noms de chemin habituels:

URL url = classLoader.getResource("com/example/file.ext");
// ...

ou

InputStream input = classLoader.getResourceAsStream("com/example/file.ext");
// ...
2
BalusC

En supposant que l'utilisateur n'entre pas le chemin d'accès complet au fichier et saisit quelque chose comme "mon nom de fichier uniquement". File file = new File(".", args[0]) est nécessaire dans ce cas pour localiser le fichier (en faisant attention au premier argument passé).

Toutes les plates-formes: File.getParent() ne renvoie pas le répertoire parent, il doit retourner ".." ou le nom du répertoire parent d'une manière spécifique au système de fichiers.

Si vous créez le fichier "myfilenameonly" sans spécifier le chemin d'accès complet au répertoire où il se trouve, la File.getParent(), par exemple, renverra null.

Voir plus loin: http://bugs.Sun.com/bugdatabase/view_bug.do?bug_id=1228537

1
Marcos Leão