2010-05-08 12 views
19

Wenn ich eine Java-Anwendung ausführen, die aus einer Datei in Eclipse lesen sollte, bekomme ich eine java.io.FileNotFoundException, obwohl die Datei im richtigen Verzeichnis ist. Ich kann die Anwendung über die Befehlszeile kompilieren und ausführen. Das Problem tritt nur in Eclipse mit mehr als einem Projekt und einer Anwendung auf. Gibt es eine Einstellung, die ich in den Laufkonfigurationen ändern oder Pfade erstellen muss, damit die Datei korrekt gefunden wird?Java kann Datei nicht finden, wenn sie durch Eclipse läuft

+1

Ohne Ihren Code zu sehen, können wir Ihnen nicht sagen, was passieren könnte –

Antwort

28

Das Problem ist sehr wahrscheinlich, dass Ihre Anwendung einen relativen Pfadnamen verwendet. Wie @BalusC sagt, können relative Pfadnamen problematisch sein. Aber IMO, er geht viel zu weit, wenn er sagt "[y] ou sollte nie relative Pfade in java.io stuff". Wenn eine Anwendung eine Datei mit dem Konstruktor FileInputStream(File) öffnet, werden relative Pfadnamen relativ zum "aktuellen Verzeichnis" in einem Prozess aufgelöst, der im Javadoc für File.getAbsolutePath() wie folgt beschrieben wird.

[...] Ansonsten wird dieser Pfadname systemabhängig aufgelöst. Auf UNIX-Systemen wird ein relativer Pfadname als absolut festgelegt, indem er für das aktuelle Benutzerverzeichnis aufgelöst wird. Auf Microsoft Windows-Systemen wird ein relativer Pfadname absolut gemacht, indem er für das aktuelle Verzeichnis des Laufwerks aufgelöst wird, das durch den Pfadnamen benannt wird, falls vorhanden; Wenn nicht, wird es gegen das aktuelle Benutzerverzeichnis aufgelöst.

So sofort sehen wir, dass der Begriff des „aktuellen Verzeichnisses“ unterschiedliche Nuancen auf Windows und UNIX-Plattformen hat. Das zweite Problem ist, dass Sie in reinem Java nicht definitiv herausfinden können, was das aktuelle Verzeichnis ist, und Sie können es sicherlich nicht für die aktuelle JVM mit reinem Java ändern. (Beim Start der JVM wird die Systemeigenschaft "user.dir" auf das aktuelle Verzeichnis gesetzt, aber gibt es nichts, was eine Anwendung davon abhält, die Eigenschaft zu ändern, so dass Sie sich nicht vollständig darauf verlassen können. Außerdem "benutzer.dir" ändern ändert nur die Art, wie der leere Pfad aufgelöst wird, nicht relative Pfade im Allgemeinen.)

Was sollten Sie also tun?

  • Eine Option besteht darin, absolute Pfadnamen für Dateien zu verwenden. Dies ist in (fast) allen Fällen zuverlässig, aber die Verwendung absoluter Pfadnamen kann problematisch sein, wenn der Benutzer den Pfadnamen eingeben muss, oder , wenn Sie festverdrahtete (oder konfigurierte) absolute Pfadnamen vermeiden müssen.

  • Eine zweite Option besteht darin, relative Pfadnamen für Klassenpfad zu verwenden und Dateien relativ zum Installationsverzeichnis der Anwendung zu suchen. Dies funktioniert, wenn Sie das tun müssen, aber es stellt ein Problem dar, wenn Sie eine File an eine Bibliotheksmethode übergeben müssen. Es hilft auch nicht, wenn Sie versuchen, die Anwendungspräferenzen des Benutzers zu finden. (Im Allgemeinen ist die Eingabe von Benutzereinstellungen in das Installationsverzeichnis ein Fehler ...)

  • Eine dritte Option besteht darin, eine Datei relativ zu einem absoluten Verzeichnis zu benennen, das Sie von einem anderen Verzeichnis beziehen. z.B. new File(System.getProperty("home.dir"), "foo/bar");.

  • Die letzte Option ist relative Pfadnamen zu verwenden, und geht davon aus, dass der Benutzer zu wissen, was das aktuelle Verzeichnis. Für viele Anwendungen, die der Benutzer über die Befehlszeile ausführt, ist dies die richtige Lösung.

  • In dem speziellen Fall von Eclipse gibt es eine einfache Lösung. Wechseln Sie zu der "run configuration", die Sie zum Starten Ihrer Anwendung verwenden, öffnen Sie die Registerkarte "Argumente" und klicken Sie auf das Optionsfeld "Andere". Geben Sie dann einen absoluten Pfadnamen als Arbeitsverzeichnis für die gestartete Anwendung ein. Wenn die untergeordnete JVM gestartet wird, hat sie das angegebene Arbeitsverzeichnis als ihr aktuelles Verzeichnis.

    +0

    Danke für Ihre Hilfe! – derekerdmann

    +0

    Hatte ein Problem mit meiner App gestartet von Eclipse nicht in der Lage, einige Eigenschaften Datei zu lesen, die im Stamm meines Projekts war.Nachdem ich versucht habe, das Arbeitsverzeichnis in der Laufkonfiguration auf $ {workspace_loc}/myproject/bin zu setzen, funktionierte es! – Krishnaraj

    +0

    @Krishnaraj - Das habe ich im letzten Abschnitt meiner Antwort gesagt :-) –

    6

    Wenn Sie eine Standard-Java-Anwendung in Eclipse erstellen, können Sie diese Verzeichnisstruktur erhalten:

    ./ProjectName/ - Stammverzeichnis
    ./ProjectName/bin/ - Ausgabeverzeichnis, .class- enthalten
    Dateien ./ProjectName/src/ - Quellverzeichnis enthält .java-Dateien

    Wenn Ihre Anwendungsanforderungen „./data.txt“ es für sie in Bezug auf das root-Verzeichnis suchen. Dies ist das "Arbeitsverzeichnis" und kann auf der Registerkarte "Argumente" gemäß der obigen Antwort von Martin konfiguriert werden.

    Sie sagen, es funktioniert über die Befehlszeile? Dies liegt wahrscheinlich daran, dass Sie sich beim Ausführen der Java-Binärdatei entweder in den Ordnern bin oder src befinden. Das Arbeitsverzeichnis ist in diesem Fall das Verzeichnis, in dem sich die Eingabeaufforderung gerade befindet. Wenn Sie zum Beispiel in das Verzeichnis/src/gehen, sagen Sie javac *.java, dann führen Sie die Dateien von dort aus, es wird nach "./data.txt" im Verzeichnis/src/suchen. Wenn Sie in das Verzeichnis/bin/gehen und Ihre Anwendung von dort ausführen, sucht es nach der Datei relativ zum Verzeichnis/bin /.

    +0

    Vielen Dank für Ihre Hilfe. Die Textdateien, die ich brauche, existieren im Verzeichnis/bin /, das scheint also nicht das Problem zu sein. Ich werde mit relativen Pfaden spielen und sehen, was ich bekommen kann. – derekerdmann

    2

    Sie sollten nie relative Pfade in java.io Zeug verwenden. Der Pfad hängt vom aktuellen Arbeitsverzeichnis ab, das davon abhängt, wie Sie die Anwendung gestartet haben, und ist daher nicht in allen Umgebungen gleich. Dies ist in der Java-Anwendung nicht kontrollierbar. Portabilitätsprobleme! Verwenden Sie immer absolute Pfade. So z.B. c:/path/to/file.ext oder /path/to/file.ext (mit dem führenden Schrägstrich) für UNIX und Consorts (oder sogar Windows, wenn der Laufwerksbuchstabe irrelevant ist).

    Wenn Sie einige Dateien zusammen mit Ihrer Anwendung versenden möchten, ist es üblich, sie auch im Klassenpfad zu platzieren. Auf diese Weise können Sie einfach ClassLoader#getResource() verwenden, um seinen Standort zu erhalten. Es gibt eine URL zurück. Sie können URL#toURI() oder URL#getPath() verwenden und an den Konstruktor java.io.File übergeben und dann weiter verwenden.

    In Ihrem Eclipse-Projekt ist der Ordner src (in dem sich Ihre Java-Quelle befindet) im Grunde der Stamm des Klassenpfads. Darüber hinaus deckt es natürlich auch alle anderen Projekte und (externen) Ordner ab, die im Build Path des Projekts erstellt wurden.

    Unter der Annahme, dass Sie die bestimmte Datei in der Wurzel platziert haben der Classpath:

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

    Sie sogar ClassLoader#getResourceAsStream() direkt eine InputStream können erhalten:

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

    Wenn sie gesetzt wird Innerhalb eines Pakets können Sie dann einfach die üblichen Pfadnamen verwenden:

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

    oder

    InputStream input = classLoader.getResourceAsStream("com/example/file.ext"); 
    // ... 
    
    +0

    Eine nicht-GUI-Befehlszeilenanwendung kann vernünftigerweise so entworfen werden, dass relative Pfadnamen verwendet werden. Der Nachteil ist, dass der Benutzer das Konzept des "aktuellen Verzeichnisses" verstehen muss, und der Programmierer muss verstehen, wie dies dem Verhalten der Java IO-Bibliotheken entspricht. –

    +0

    @Stephen: Es ist sicherlich möglich, werden Sie nur mit relativen Pfaden Ärger haben, aber es wird nicht empfohlen. Die Verwendung des Klassenpfads macht es robuster. – BalusC

    +0

    hängt davon ab, was die Anwendung tut. Wenn zum Beispiel Dateien vom Benutzer bearbeitet werden, ist der Classpath-Ansatz wenig sinnvoll. –

    1

    Angenommen, der Benutzer gibt nicht den vollständigen Dateipfad zur Datei ein und gibt etwas wie "myfilenameonly" ein. File file = new File(".", args[0]) ist notwendig, in diesem Fall zu suchen Sie die Datei (die Aufmerksamkeit auf das erste Argument die Zahlung bestanden).

    Alle Plattformen: File.getParent() kehrt nicht das übergeordnete Verzeichnis, sollte zurückgeben „..“ oder der Name des übergeordneten Verzeichnisses in einer Datei-System spezifische Art und Weise.

    Wenn Sie die Datei „myfilenameonly“ ohne Angabe des vollständigen Pfad in das Verzeichnis erstellen, in dem es sich befindet, die File.getParent(), zum Beispiel, wird null zurück.

    Sehen Sie weitere: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=1228537

    2

    ich ein ähnliches Problem mit war, ich meine Dateien in einem Ordner mit dem Namen cobolcopybooks innerhalb des src-Ordner abgelegt und versucht, sie in meinem Projekt zugreifen classloader.getResource mit ("cobolcopybooks/demostud. cob ") aber ich war null-Zeiger Ausnahme bekommen, habe ich versucht, es mehrmals durch die Reinigung und den Aufbau der Arbeitsbereiche nach mehreren gescheiterten Versuchen wird mir klar, dass ich das Projekt nicht war erfrischend, die Dateien zu erlauben, zusammen mit dem Projekt gebaut werden. Diese Dateien sollten zusammen mit anderen Klassendateien sichtbar sein, denn zur Laufzeit ist das Stammverzeichnis das Verzeichnis bin und sucht dort nach diesen Dateien.

    8

    Eine andere Möglichkeit ist, einfach herauszufinden, was Verzeichnis mit den „Strompfad“ Punkte in Ihrer Umgebung - was auch immer das ist. Sobald Sie herausgefunden haben, können Sie Ihre Lösung von dort wählen. Vielleicht verwenden Sie einen geeigneten relativen Pfad zum Speicherort Ihrer Datei oder verschieben die Datei.

    +1

    Dies ist nicht ideal in der Liefer-Code, aber es ist definitiv nützlich als Debug-Code, um zu sehen, was Ihre Anwendung denkt. – Steve

    Verwandte Themen