Sonic: Das System kann die Datei nicht finden

Hallo,

brauch dringend eure Hilfe, und zwar, wenn Dateien auslesen möchte, kommt immer Fehlermeldung: "Das System kann die Datei nicht finden".

Die Datei existiert 100%. Mit absoluten Pfad wird die Datei gefunden, mit relativen nicht. Hier ist ein Beispiel:

###############################################
File datei = new File("ordner/datei.txt");
System.out.println(datei.exists());                  //false
###############################################

És geht auch nicht, wenn ich die Datei in den Ordner lege, wo auch die Klasse selbst ist (new File("datei.txt")).

Danke im Voraus.

  1. Hallo,

    Die Datei existiert 100%. Mit absoluten Pfad wird die Datei gefunden, mit relativen nicht. Hier ist ein Beispiel:

    ###############################################
    File datei = new File("ordner/datei.txt");
    System.out.println(datei.exists());                  //false
    ###############################################

    És geht auch nicht, wenn ich die Datei in den Ordner lege, wo auch die Klasse selbst ist (new File("datei.txt")).

    Nunja, das kann daran liegen, dass Du die Klasse nicht in dem gleichen Verzeichnis ausführst, in dem sie auch liegt.

    Beispiel:

    In /home/christian/tmp/java liegt eine Datei "dateia.class" die eben Deinen Code new File ("datei.txt") macht und dann ausgibt, ob sie existiert.

    Führe ich in /home/christian/tmp/java folgenden Befehl aus:

    java dateia

    Dann erhalte ich:

    true

    als Ausgabe (d.h. die Datei existiert). Führe ich dagegen IRGENDWO anders (d.h. in einem anderen Verzeichnis) folgenden Befehl aus:

    java -cp /home/christian/tmp/java dateia

    dann erhalte ich:

    false

    als Ausgabe.

    Führe doch mal folgenden Code aus:

    System.out.println (new File (".").getCanonicalPath ());

    Das gibt Dir aus, in welchem Verzeichnis Du Dich befindest, wenn Du Deine Java-Datei ausführst. Alle Pfade müssen relativ zu DEM Verzeichnis sein (oder Du musst vor der Java-Ausführung das Verzeichnis wechseln).

    Viele Grüße,
    Christian

    1. System.out.println (new File (".").getCanonicalPath ());

      Das gibt Dir aus, in welchem Verzeichnis Du Dich befindest, wenn Du Deine Java-Datei ausführst. Alle Pfade müssen relativ zu DEM Verzeichnis sein (oder Du musst vor der Java-Ausführung das Verzeichnis wechseln).

      Viele Grüße,
      Christian

      So, ich habe gerade den aktuellen Pfad ausgegeben. Er zeigt mir das Wurzelverzeichnis, also da, wo meine Projekt-Datei liegt (benutze Eclipse). Muss ich jetzt den ganzen langen Pfad für die Datei angeben? Es muss irgendwie anders gehen, oder? Wo muss ich was einstellen?

      Danke.

      1. Hallo,

        So, ich habe gerade den aktuellen Pfad ausgegeben. Er zeigt mir das Wurzelverzeichnis, also da, wo meine Projekt-Datei liegt (benutze Eclipse).

        Dann führt Eclipse Deine Klasse im Wurzelverzeichnis aus.

        Öhm, dazu noch ne weitere Frage: Ist in Deiner Klasse die main-Methode enthalten (d.h. wird diese direkt aufgerufen) oder wird die Klasse nur von einem anderen Teil der Software verwendet? Wenn ich das weiß, kann ich Dir auch folgende Frage beantworten:

        Muss ich jetzt den ganzen langen Pfad für die Datei angeben? Es muss irgendwie anders gehen, oder?

        Viele Grüße,
        Christian

        1. Dann führt Eclipse Deine Klasse im Wurzelverzeichnis aus.

          Ja, so ist es.

          Öhm, dazu noch ne weitere Frage: Ist in Deiner Klasse die main-Methode enthalten (d.h. wird diese direkt aufgerufen) oder wird die Klasse nur von einem anderen Teil der Software verwendet? Wenn ich das weiß, kann ich Dir auch folgende Frage beantworten:

          Ich habe die Main-Methode und den Code zu Auslesen in einer Klasse stehen (nur zum Testen so gemacht, später werde ich die
          Main entfernen). Wenn ich das Programm aus einer anderer Klasse heraus aufrufe, ändert sich nichts. Die Datei wird nicht gefunden.

          Danke dir.

          1. Hallo,

            Öhm, dazu noch ne weitere Frage: Ist in Deiner Klasse die main-Methode enthalten (d.h. wird diese direkt aufgerufen) oder wird die Klasse nur von einem anderen Teil der Software verwendet? Wenn ich das weiß, kann ich Dir auch folgende Frage beantworten:

            Ich habe die Main-Methode und den Code zu Auslesen in einer Klasse stehen (nur zum Testen so gemacht, später werde ich die
            Main entfernen). Wenn ich das Programm aus einer anderer Klasse heraus aufrufe, ändert sich nichts. Die Datei wird nicht gefunden.

            Oh, das ist natürlich irgendwie doof.

            Denn: Du kannst mittels getResource / getResourceAsStream (wie Daniel vorschlug) durchaus Resourcen relativ zum Classpath auflösen.

            Wenn Du allerdings Deine Klasse in einem Unterverzeichnis hast und dort testhalber main() reintust, dann wird Eclipse den Classpath beim Ausführen automatsich auf Dein Unterverzeichnis setzen - sprich: Du kannst das dann auflösen.

            Wenn Du Deine Klasse dagegen nur als Teil eines Pakets verwendest und von einer anderen Klasse in einem höherliegenden Verzeichnis aufrufst, dann ist der Classpath beim Ausführen auf das höherliegende Verzeichnis gesetzt und die Klasse, die Deine Klasse aufruft, ruft diese ja über a.b.c.Klasse auf, wobei das im Dateisystem dann als a/b/c/Klasse.class aufgelöst wird.

            Wenn Du relativ zum Classpath was auflösen willst, dann kannst Du folgendes verwenden:

            java.net.URL url = getClass ().getResource ("relativer/pfad/vom/Classpath/aus/zu/datei.txt");  
            if (url == null) { // nicht gefunden  
              // ...  
            } else {  
              // ne datei draus machen  
              java.io.File file = new java.io.File (url);  
            }
            

            Das bringt Dir aber wie gesagt nur dann einen Pfad relativ zu Deiner Klasse, wenn Deine Klasse direkt im Classpath hockt und nicht noch in einem Paket ist (d.h. am Anfang der Datei package a.b.c; steht).

            Und wenn Du das ganze noch in eine *.jar packst, dann hast Du ganz verloren, dann funktioniert der obige Code zum einen nicht mehr (weil new File (url) davon ausgeht, dass url mit file:/// anfängt und wenn das nicht der Fall ist, gibt's ne schöne Exception) und zum anderen kannst Du dann nur noch lesend auf die Resource zugreifen (indem Du Dir z.B. analog über getResourceAsStream () einen InputStream zurückgeben lässt). Schreiben kannst Du aber auf Dinge in *.jar-Dateien nicht. Sagte aber Daniel hier im Thread bereits schon.

            Viele Grüße,
            Christian

        2. Öhm, dazu noch ne weitere Frage: Ist in Deiner Klasse die main-Methode enthalten (d.h. wird diese direkt aufgerufen) oder wird die Klasse nur von einem anderen Teil der Software verwendet? Wenn ich das weiß, kann ich Dir auch folgende Frage beantworten:

          Muss ich jetzt den ganzen langen Pfad für die Datei angeben? Es muss irgendwie anders gehen, oder?

          Viele Grüße,
          Christian

          Hi Christian, könntest du mir bitte die Frage doch noch beantworten?

      2. Hallo,

        So, ich habe gerade den aktuellen Pfad ausgegeben. Er zeigt mir das Wurzelverzeichnis, also da, wo meine Projekt-Datei liegt (benutze Eclipse). Muss ich jetzt den ganzen langen Pfad für die Datei angeben? Es muss irgendwie anders gehen, oder? Wo muss ich was einstellen?

        Willst du wirklich eine Datei im aktuellen Arbeitsverzeichnis finden?
        Oder reicht es auch, wenn sie im Classpath liegt? Oftmals liefert man
        fertige Java-Applikation in einem einzigen JAR-Archiv aus und liest
        Dateien (z.B. unveränderliche Ressourcen etc.) aus diesem JAR-Archiv aus.
        Das geht über den Classloader. Willst du eigentlich das tun, dann frag
        bitte nochmal nach.

        Oder willst du tatsächlich eine Datei aus dem aktuellen Arbeitsverzeichnis
        auslesen? Dann kannst du, solange du das Programm in Eclipse ausführst,
        im Run-Dialog im Tab "Arguments" unten ein anderes Arbeitsverzeichnis
        (Working Directory) einstellen, z.B. auch relativ zum Projektverzeichnis.

        Gruß
        Slyh

        1. Willst du wirklich eine Datei im aktuellen Arbeitsverzeichnis finden?

          Nein, in einem Verzeichnis höher, nicht im aktuellen Verzeichnis.

          Oder reicht es auch, wenn sie im Classpath liegt? Oftmals liefert man
          fertige Java-Applikation in einem einzigen JAR-Archiv aus und liest
          Dateien (z.B. unveränderliche Ressourcen etc.) aus diesem JAR-Archiv aus.
          Das geht über den Classloader. Willst du eigentlich das tun, dann frag
          bitte nochmal nach.

          Ich habe schon mal was über den Classloader gehört, aber weiß jetzt nicht genau was er macht. Wo ist der Unterschied, ob ich eine Datei über den Classloader öffne oder auf dem klassischen Wege?

          Oder willst du tatsächlich eine Datei aus dem aktuellen Arbeitsverzeichnis
          auslesen? Dann kannst du, solange du das Programm in Eclipse ausführst,
          im Run-Dialog im Tab "Arguments" unten ein anderes Arbeitsverzeichnis
          (Working Directory) einstellen, z.B. auch relativ zum Projektverzeichnis.

          Mir geht es darum, dass die Datei immer gefunden wird, also auch dann, wenn ich nicht mehr mit Eclipse arbeite.

      3. Hallo Sonic,

        Wo genau soll die Datei denn liegen?
        Wenn Die Datei Teil Deiner Anwendung sein soll, solltest Du Dir die Methoden Class.getResource und Class.getResourceAsStream ansehen.

        Grüße

        Daniel

        1. Hallo Sonic,

          Wo genau soll die Datei denn liegen?
          Wenn Die Datei Teil Deiner Anwendung sein soll, solltest Du Dir die Methoden Class.getResource und Class.getResourceAsStream ansehen.

          Grüße

          Daniel

          Hi Daniel,
          die Datei ist ein Teil meines Programms. Da es eine Textdatei ist, die ich fürs Speichern bestimmter Daten verwende, wollte ich sie in einem dafür extra angelegtem Ordner speichern.

          1. Hallo Sonic,

            Du willst darin Daten speichern?
            Dann kannst Du das nicht so machen wie von mir vorgeschlagen, das funktioniert nur, um unveränderliche Daten zu lesen, die Teil des Programmes sind.

            Daten sollte ein Programm nie in dem Verzeichnis ablegen, in dem es installiert ist. Spätestens bei Umgebungen mit mehreren Nutzern geht das in die Hose.
            Es empfiehlt sich, solche Dinge in ein Unterverzeichnis des Home-Verzeichnisses des Anwenders zu speichern.
            Das Home-Verzeichniss erfährst Du mit: System.getProperty("user.home")
            Das Verzeichnis für das Programm nennt man unter Unix dann typischerweise ".programmname" (mit dem Punkt).
            Was user.home unter Windows liefert, weiß ich nicht mehr genau, vermutlich die "Eigenen Dateien". Das ist zwar nicht der optimale Ort unter Windows um direkt solche Daten abzulegen, aber immer noch besser, als das Programm-Verzeichnis zu verwenden.
            Wenn man will, kann man auch noch abfragen, ob es sich für Windows handelt (und evtl um welches) und dann relativ zum Home-Verzeichnis dieses Verzeichnis für Anwendungsdaten raussuchen.

            Grüße

            Daniel

            1. .............
              Wenn man will, kann man auch noch abfragen, ob es sich für Windows handelt (und evtl um welches) und dann relativ zum Home-Verzeichnis dieses Verzeichnis für Anwendungsdaten raussuchen.

              Danke Daniel.
              Die Datei soll plausible Daten (Highscore) beinhalten. Die ist für alle Benutzer gleich. Also ich denke, die soll einem Programmverzechnis liegen, z.B. save/bestenliste.txt

              1. Hallo,

                Die Datei soll plausible Daten (Highscore) beinhalten. Die ist für alle Benutzer gleich. Also ich denke, die soll einem Programmverzechnis liegen, z.B. save/bestenliste.txt

                Nunja, dann ist die Frage: Wie bekommst Du das "Programmverzeichnis" heraus? Ich halte das für eine ziemlich nichttriviale Aufgabe.

                Im Prinzip müsstest Du den kompletten Classpath durchgehen und dort dann jeweils nach Deiner Klasse suchen. Wenn der Eintrag des Classpath ein Verzeichnis ist, dann suchst Du dort nach Deiner Klasse (im richtigen Unterverzeichnis). Existiert diese, dann ist dieser Eintrag Deines Classpaths Dein Programmverzeichnis. Wenn der Eintrag des Classpaths eine *.jar-Datei ist, dann suchst Du, ob innerhalb diese *.jar-Datei Deine Klasse ist. Wenn dies der Fall ist, ist das Verzeichnis, das die *.jar-Datei enthält, Dein Programmverzeichnis. Und wenn Du Deine Klasse gar nicht findest (weil z.B. der Classpath inzwischen geändert wurde), dann bist Du ziemlich aufgeschmissen.

                Dein Problem ist, dass Java das Konzept "Programmverzeichnis" in der Form nicht kennt. Das Java-Konzept sieht sowas nämlich nicht vor. Mit Java kannst Du nämlich durchaus ganz einfach sowas machen wie

                java -jar /pfad/zur/jar/des/programms.jar

                und damit ein Programm ausführen - das Programm wäre dann komplett in dieser .jar-Datei enthalten. Diese .jar-Datei könnte zusammen in einem Verzeichnis mit lauter anderen .jars liegen, die nichts mit dem Programm zu tun haben und andere Programme enthalten. Dann gäbe es gar kein Programmverzeichnis oder höchstens eins, das von allen geteilt wird.

                Am sinnvollsten wäre es doch, das Verzeichnis für die Highscores wäre irgendwie konfigurierbar. Wenn Du Dein Programm irgendwo installierst, dann starten die User das ja sicher nicht über java .... auf der Kommandozeile, sondern über etwas anderes - unter Windows eine Batch-Datei, unter Linux ein Shell-Script etc. Wenn Du nun die Batch-Datei / das Shell-Script erkennen könnten, in welchem Verzeichnis sie sich befinden (bzw. das müssen sie ja sowieso, um den Classpath korrekt zu setzen, wenn sie java korrekt aufrufen wollen) können sie beim Aufruf des Java-Interpreters PROBLEMLOS auch übergeben (z.B. per Umgebungsvariable), welches Verzeichnis das ist, so dass Dein Programm das Programmverzeichnis kennt. Und in Deiner Entwicklungsumgebung kannst Du Eclipse sicher so konfigurieren, dass dort die Umgebungsvariable auf ein Testverzeichnis gesetzt wird. Das wäre in meinen Augen die sinnvollste Lösung.

                Viele Grüße,
                Christian

              2. Hallo,

                Danke Daniel.
                Die Datei soll plausible Daten (Highscore) beinhalten. Die ist für alle Benutzer gleich. Also ich denke, die soll einem Programmverzechnis liegen, z.B. save/bestenliste.txt

                Und das wäre eine Information gewesen, die schon deutlich früher hätte
                kommen können.

                Also, erstmal ist der vorgesehene Pfad für Benutzerdaten in eigentlich
                jedem Betriebssystem _nicht_ das Programmverzeichnis. Leider kommt man
                mit Java direkt aber auch nicht an das Datenverzeichnis aller Benutzer
                ran. (Unter Windows wäre dies z.B. C:\Dokumente und Einstellungen\All
                Users\Anwendungsdaten)

                Das Problem mit aktuellen Arbeitsverzeichnissen ist, daß sie nicht mit
                dem Installationsverzeichnis übereinstimmen müssen. Du kannst deine
                Applikation z.B. auch aufrufen, wenn du dich gerade im Verzeichnis c:\temp
                befindest, obwohl dein Programm unter F:\Programme\MeinSpiel\ installiert
                ist.

                Davon abgesehen, gibt es nicht auf jedem Betriebssystem ein aktuelles
                Arbeitsverzeichnis. WinCE kennt beispielweise gar kein aktuelles
                Arbeitsverzeichnis. Dort ist immer Root () das Arbeitsverzeichnis.

                In C kommt man u.U. an das Verzeichnis, in dem sich auch die zur Zeit
                laufende EXE befindet, ran. Unter Java kann man meistens auch rausfinden,
                von welcher Stelle eine .class-Datei ausgeführt wird.

                Ich hatte hierzu schonmal was geschrieben.

                Problem: Eine .class-Datei muß nicht zwingend von einem Datenträger
                geladen worden sein, sondern könnte auch über eine URL bezogen oder gar
                dynamisch generiert worden sein.

                Ich poste trotzdem mal (ohne Funktionsgarantie!) einen Code, der das
                Verzeichnis ermitteln kann, in dem sich die Klasse befindet, in dem
                sich diese Methode befindet. Wenn sich die Klasse in einem JAR befindet,
                wird das Verzeichnis zurückgeliefert, wo sich das JAR-Archiv befindet.

                Der Code funktioniert mit ziemlicher Sicherheit nicht auf allen Plattformen
                und schon gleich gar nicht, wenn die .class-Datei über eine URL oder
                anderweitig erzeugt wurde.

                  
                protected File findInstallationDirectory() throws InstallationDirectoryNotFound  
                {  
                    CodeSource classCodeSource = getClass().getProtectionDomain().getCodeSource();  
                    if (classCodeSource == null) {  
                        throw new InstallationDirectoryNotFound("Code Source is null");  
                    }  
                  
                    URL classLocation = classCodeSource.getLocation();  
                  
                    if (classLocation.getProtocol().equals("file")) {  
                        // Use file:// URL as is.  
                        try {  
                            installationDirectory = new File(classLocation.toURI());  
                        } catch (URISyntaxException e) {  
                            throw new InstallationDirectoryNotFound("URISyntaxException: " + e);  
                        }  
                  
                    } else if (classLocation.getProtocol().equals("jar")) {  
                        // Extract file:// URL of JAR file from URL (jar:file:/c:/path/file.jar!/file.class)  
                  
                        // getPath() cuts away "jar:". (-> file:/c:/path/file.jar!/file.class)  
                        String path = classLocation.getPath();  
                  
                        // Remove file.class. Separator is "!/". (-> file:/c:/path/file.jar)  
                        int sheSlashPos = path.lastIndexOf("!/");  
                        if (sheSlashPos != -1) {  
                            path = path.substring(0, sheSlashPos);  
                        }  
                  
                        return new File(path);  
                    }  
                  
                    // Neither "file" nor "jar" protocol.  
                    throw new InstallationDirectoryNotFound("Game class is neither a file nor inside a JAR archive.");  
                }  
                
                

                Gruß
                Slyh

  2. Hallo,

    brauch dringend eure Hilfe, und zwar, wenn Dateien auslesen möchte, kommt immer Fehlermeldung: "Das System kann die Datei nicht finden".

    Nun, offensichtlich ist dein aktuelles Verzeichnis ein anderes als
    du denkst. Du kannst das aktuelle Verzeichnis über folgenden Code
    herausfinden:
    System.getProperty("user.dir");

    Oder indem du eine File-Objekt des aktuellen Verzeichnisses erzeugst
    (new File(".")) und daraus einen absoluten Pfad machst und ihn ausgibst.

    Nächstes Mal könntest du übrigens noch eine Frage formulieren. Nur ein
    Problem zu schildern, führt oft dazu, daß niemand weiß, was er/sie jetzt
    genau antworten soll. :)

    Gruß
    Slyh