Textdatei aus den Ressourcen lesen

Hallo Community,
für mein Programm möchte ich eine Textdatei erstellen, in die ich Variablen schreiben kann, sodass sie beim Beenden nicht verloren gehen.

Nun habe ich das auch mit:

f = new File("./users/list.txt");
		
		try{
			s = new Scanner(f);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

für einen “absoluten” Pfad hinbekommen. (also dass die .jar, in einem Ordner liegt, in dem auch der Ordner “user” ist mit der list.txt-Datei)

Jetzt würde ich die Textdatei gerne in die Ressourcen speichern.
Aber wie komme ich jetzt an diese ran?
Ich habe es mit:

		URL url = getClass().getResource("/users/list.txt");
		f = new File(url.toString());
		
		try{
			s = new Scanner(f);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

versucht, aber dann kommt immer die FileNotFoundException.

HaveANiceDay

Du könntest einen relativen Pfad verwenden

new File("users/list.txt");

.

Gruß

[QUOTE=Firephoenix]Du könntest einen relativen Pfad verwenden

new File("users/list.txt");

.

Gruß[/QUOTE]

Das klappt irgendwie nicht.
Wenn ich mein Programm als “Runable JAR file” exportiere und die Textdatei nicht mit in den Ordner lege geht das nicht.

Mit Bildern ging das immer recht einfach:

IconLabel.setIcon(new ImageIcon(getClass().getResource("/Images/picture.png")));

du kannste in die laufende JAR nicht reinspeichern sondern nur aus ihr lesen
aus diesem grund gibt es auch nur die methode InputStream getResourceAsStream()

beim start sperrt java automatisch das jar exklusiv, also auch “von außen reinschreiben” fällt flach

musst du daten speichern bleibt dir nur die möglich ins dateisystem, ins jar geht nicht

Dein Ansatz war schon richtig, das Problem ist nur, dass dein Ordner “users” nicht im Classpath drin ist. Du müsstest dafür “.” mit in den Classpath aufnehmen, entweder in MANIFEST.MF für das Jar oder eben beim Aufruf:

java -cp . -jar foobar.jar

Dann befindet sich auch der Ordner “users” im Classpath und die Datei wird auch gefunden.

oder die standard-zeile für einen absoluten pfad
File dir=(new File(this.getClass().getProtectionDomain().getCodeSource().getLocation().toURI())).getParentFile();
wenn aus einem JAR ausgeführt zeigt “dir” auf den ordner in dem das JAR liegt

[QUOTE=Akeshihiro]Dein Ansatz war schon richtig, das Problem ist nur, dass dein Ordner „users“ nicht im Classpath drin ist. Du müsstest dafür „.“ mit in den Classpath aufnehmen, entweder in MANIFEST.MF für das Jar oder eben beim Aufruf:

java -cp . -jar foobar.jar

Dann befindet sich auch der Ordner „users“ im Classpath und die Datei wird auch gefunden.[/QUOTE]

Der Ordner „users“ liegt im Ordner „res“, welchen ich zum Build Path hinzugefügt habe.

Ich möchte die Textdatei benutzten um den Ordner-Pfad zu speichern in dem das Spiel „installiert“ ist.
(Ich würde ungern in die Registry schreiben, da ich da nichts kaputt machen möchte, wenn ich ein Fehler mache).

So dass die jar irgendwo liegen kann, die Speicherdaten jedoch an einer anderen Stelle.
Aber vielleicht ist das keine so gute Idee. Ich sollte die JAR einfach mit in den Ordner legen in dem die Speicherdaten sind oder?

Bei meiner Idee habe ich mich am Spiel „Minecraft“ inspiriert.
Die Minecraft.exe kann ich überall auf der Festplatte ablegen.
Die Speicherdatein, wie Spielwelten liegen dann irgendwo in %appdata%/roaming/.minecraft/…
Diesen Pfad kann man Launcher jedoch auch ändern.

Dein Buildpath gilt aber nur für Eclipse, nicht für die Jar, die schlussendlich erzeugt wird. Startest du die Jar, ist nur das im Classpath eingetragen, was auch im Manifest drin steht und sonst nichts. Was in deinem Build-Path drin steht, ist also vollkommen egal, der gilt nur für die Entwicklungsarbeiten, aber nicht für das Deployment. Und eben der Ordner des Jars, also “.”, fehlt bei dir anscheinend, daher wird auch nichts gefunden.

Was ich jetzt nicht ganz verstehe ist, warum das dann bei den Bilder funktioniert.
So sind die Ordner aufgebaut.

res (BuildPath)

  • Images
    [INDENT]-> picture.png[/INDENT]
  • users
    [INDENT]-> list.txt[/INDENT]

Das geht:

IconLabel.setIcon(new ImageIcon(getClass().getResource("/Images/picture.png")));

Das geht nicht:

		URL url = getClass().getResource("/users/list.txt");
		f = new File(url.toString());
		
		try{
			s = new Scanner(f);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

Wenn die Datei in der .jar ist klappt das mit dem File-Object nicht. Falls du in die Datei schreiben willst sollte sie aber sowieso nicht in der .jar sondern neben der .jar liegen.
z.b.
myapp.jar
users
—list.txt

Dann klappt auch der obige Aufruf.

Gruß

[QUOTE=Firephoenix]Wenn die Datei in der .jar ist klappt das mit dem File-Object nicht. Falls du in die Datei schreiben willst sollte sie aber sowieso nicht in der .jar sondern neben der .jar liegen.
z.b.
myapp.jar
users
—list.txt

Dann klappt auch der obige Aufruf.

Gruß[/QUOTE]

Ja, so werde ich das jetzt wahrscheinlich machen.

[QUOTE=HaveANiceDay]Was ich jetzt nicht ganz verstehe ist, warum das dann bei den Bilder funktioniert.
So sind die Ordner aufgebaut.

res (BuildPath)

  • Images
    [INDENT]-> picture.png[/INDENT]
  • users
    [INDENT]-> list.txt[/INDENT]

Das geht:

IconLabel.setIcon(new ImageIcon(getClass().getResource("/Images/picture.png")));

Das geht nicht:

		URL url = getClass().getResource("/users/list.txt");
		f = new File(url.toString());
		
		try{
			s = new Scanner(f);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

[/QUOTE]

Wenn du eine Runnable Jar erstellst und keine normale Jar, in der du alles selbst einstellst, dann wird alles, was sich im Build-Path befindet, in die Jar kopiert. Die Bilder befinden sich also innerhalb der Jar, somit innerhalb des Classpath und werden deshalb auch gefunden. Gleiches würde für list.txt gelten, aber wie Firephoenix bereits sagte, funktioniert File auf Jar-Inhalte nicht. Was du machen kannst, ist, Templates im Jar zu haben, diese zu laden und auch zu benutzen. Aber das Schreiben muss dann auf dem Dateisystem stattfinden. Wo ist egal, solange die nötigen Schreibrechte vorhanden sind.

Vielen Dank für die vielen, schnellen Antwort :slight_smile:

#solved

Ich speichere sowas normalerweise unter ~/.NameDerAnwendung.

Um dem Titel vielleicht noch gerecht zu werden:

Das Programm liest seinen eigenen Quelltext aus dem “Inneren” der Jar-Datei.
Zur Lösung deines Problems taugt es freilich nicht, da man nichts in einer zur Laufzeit ausgeführten Jar-Datei ablegen kann.
Du könntest aber vielleicht beim Beenden eine neue Jar-Datei erstellen und dort alles hinein speichern, was du zur Laufzeit neben deiner Jar abgelegt hast.

Was hindert dich daran, “user.home” zu nutzen?

Ich hab’ meinen Beitrag mal als Blog zum verlinken verfasst, weil solche Fragen ja öfters kommen.
http://forum.byte-welt.net/entries/2-Von-Arbeits-Installations-und-Resourcepfaden

Hi,

ich würde mit den java.util.prefs.Preferences doch die Registry benutzen. Das geht so einfach und man kann kaum was kaputt machen. Hier ein kleines Beispiel:

import java.io.File;
import java.util.prefs.Preferences;

public class PrefsDemo {

	public static void main(String[] args) throws Exception {

		Preferences pfad;

		// ergibt den Registry-Knoten: HKEY_CURRENT_USER\Software\JavaSoft\Prefs\meinprogramm
		pfad = Preferences.userRoot().node("meinprogramm");

		// speichert den Pfad, wo diese main ausgeführt wird
		pfad.put("installationspfad", new File(".").getAbsolutePath());

		// ein Highscore als Beispiel
		pfad.putInt("highScore", 6);

		// Ausgabe zu Demo-Zwecken
		System.out.println("Punkte = " + pfad.getInt("highScore", -1));
	}
}

Grüße

[QUOTE=momolin] Das geht so einfach und man kann kaum was kaputt machen.
[/QUOTE]

o0 ob ich sowas dann auf meinem Rechner haben möchte? ich denke kaum!

Ich ebenfalls nicht. Der Grund, warum die Registry unter Windows immer mehr zugemüllt wird, sind solche Sachen. Unter Linux kenne ich auch keine Anwendungsfall, in dem in eine Art Registry geschrieben wird (doch, etwas in der Art gibt es da auch). Der übliche Weg bei *nix-Systemen ist einen unsichtbaren Ordner im Home-Verzeichnis anzulegen und dort die ganze Konfiguration, Rankings, etc. abzulegen. Und dieser Trend scheint sich inzwischen auch in der Windows-Welt so langsam durchzusetzen. Auch wenn nicht jeder Software die Konvention mit dem Punkt als erstes Zeichen pflegt (unsichtbare Ordner bei *nix beginnen mit einem Punkt), so legen zumindest immer mehr Programme im User-Verzeichnis die Informationen ab. Ist nach meiner subjektiven Wahrnehmung zwar noch immer die Minderheit, aber es wird mehr.

Die Idee eine zentrale Ablage für Einstellungen und anderes in einer Registry war vor etlichen Jahren sicherlich nicht schlecht und ist für viele auch heute sicherlich noch eine gute Idee, aber scheinbar wandelt sich das und immer mehr Programmierer gehen einen anderen Weg, vor allem Crossplattform-Entwickler. Mit den plattformspezifischen Einzelheiten will sich inzwischen doch niemand mehr rumärgern und die Windows-Registry ist sowieso ein heikles Pflaster, da die Nebenwirkungen gravierende Folgen haben können, wenn was schief gelaufen ist.