res-Ordner für Text- und Bilddateien

beastofchaos

Bekanntes Mitglied
Hall oLeute,
Ich habe bisher Bilder, ChangeLog-Datei und I18N-Dateien immer in einem extra Pakcage in src abgelegt, aber das ist natürlich suboptimal, wenn z.B. die ganzen Bilder in src und später in bin auftauchen, wodurch das Programm gleich doppelt so schwer wiegt :/

Lösung: einen Ressourcen-Ordner, wo alle Nicht-Java-Dateien liegen!
Bloß muss ich dafür überall im Programm die Pfade ändern und den BaseName für das ResourceBundle (für die I18N) ändern. Bloß wie?

Bisher hab ich eine Datei so geladen:
Code:
Image img = new ImageIcon(class.getResource("images/somePic.png")).getImage();

Ich dachte ich müsste einfach ein "res/" dafür hängen, aber da gibts nur ne NullpointerException. Ich müsste den Pfad, in dem er sucht, - nämlich "src" - irgendwie ändern.

Das ähnliche Problem ergibt sich bei der I18N, wo sogar ein Class-Name übergeben werden muss:
Code:
private static ResourceBundle language = ResourceBundle.getBundle("internationalization.language");

(Und ja ein "res." oder "res/" davor funktioniert auch net)


Bei der I18N und dem Changelog (welcher auch mit "class.getResource()") geladen wird, ist das ja nicht schlimm, aber ich muss die Bilder irgendwie auslagern. Was empfehlt ihr mir da?

Gruß, Thomas
 
Du kannst beim Programmstart überprüfen welches OS ausgeführt wird und dann die userpfade benutzen. z.B. :

Windows: c:\user\activeuser\applicationdata\deinprogramm\images

linux: /home/activeuser/.deinprogramm/images
 
@Templarthelast last Er will doch das die Dateien später auch .jar liegen, sie aber zur Programmier-Zeit nicht zweilmal auf der Platte haben (in bin und src Ordner).

Ich nehme mal an, das die Methoden zum laden alle auf Class.getResource zurückgreifen. In dem Fall musst du noch ein "/" vor den Pfad setzten: "/res/subdir/datei", das sucht vom root Verzeichnis ausgehen, alles andere vom aktuellen Package aus.

Dein Problem beim laden von I18N Informationen versteh ich aber nicht. Wenn du sagst das es sich dabei um Klassen (?) handelt, müssten die doch sowieso genau in einem Package liegen. Ansonsten auch obige Pfadangabe.
 
"deinprogramm" bzw. ".deinprogramm" wäre in dem Fall dann eine jar-Datei. Funktioniert aber trotzdem?

Das wäre dann warscheinlich zum Bild laden, folgende Zeile:
Code:
Image img = new ImageIcon(System.getProperty("user.dir") + "res\\images\\somePic.png"

Jetzt ist halt noch die Frage, wie funktioniert das dann mit RessourceBundle für die I18N.

Danke für die Rückmeldung
 
Es sind einfache Text-Dateien, die aber für ResourceBundle als Properties-Dateien definiert werden müssen. Ich dachte mir dann halt, dass es bei Text-Dateien nicht nötig wäre, diese in src/ bin abzulegen, sondern auch in res zu verstauen.

Ich werd später das mit dem root-Verzeichnis nochmal versuchen und meld mich dann 😉
 
Ich benutze für meinen res-Ordner, welcher direkt im Unterordner der .jar liegt:
Java:
final Properties props = new Properties();
try(InputStreamReader in = new InputStreamReader( Resources.class.getResourceAsStream( "/res/properties/" + bundleName + ".properties" ), Charset.forName( "ISO-8859-1" ) );){
    props.load(in);
}
//do sth with properties
ALLERDINGS:
Wenn du im Package-Explorer von Eclipse bist, dann musst du einen Ordner "res" erstellen und IN diesem Ordner ein weiteres Package "res". Sonst erkennt er es nicht.
Wenn du später dann deine JAR entpackst, sollte ebenfalls alles funktionieren.
 
Nochmal zu den Bildern bzw. anderen Textdateien. Das hier klappt anscheinend nicht:

Code:
URL url = DInfo.class.getResource("/res/ressource/changeLog.html");

Es handelt sich umk eine Info-Datei, die ich laden will.
Das folgende klappt zwar, aber halt nur in Eclipse und nicht als jar-Datei:

Java:
String s = System.getProperty("user.dir") + "\\res\\ressource\\changeLog.html";
			BufferedReader br =
				  new BufferedReader(new FileReader(s));
			String text = br.readLine();

Freu mich auf Hilfe, Gruß Thomas
 
Wenn diese Datei im .jar liegt, kommst du mit "getResource" nicht weit.
Du musst "getResourceAsStream" benutzen für innerhalb.
Also:
Java:
BufferedReader br = new BufferedReader( new InputStreamReader( DInfo.class.getResourceAsStream("/res/resource/changeLog.html") ) );

Java:
String s = System.getProperty("user.dir") + "\\res\\ressource\\changeLog.html";
BufferedReader br = new BufferedReader(new FileReader(s));
String text = br.readLine();

Das sollte auch als .jar funktionieren!
Übrigens nur auf Windows. Besser wäre:

Java:
File dir = new File(new File(System.getProperty("user.dir"), "res"), "resource");
File f = new File(dir, "changeLog.html");
BufferedReader br = new BufferedReader(new FileReader(f));
// besser wäre hier auch noch: ... new BufferedReader(new InputStreamReader(new FileReader(f), Charset.forName("xyz"));
String text = br.readLine();

Ach mal so nebenbei: Einen Ordner "res" im "user.dir" zu erstellen sieht wahrscheinlich niemand gerne... Ändere das lieber in was Eindeutiges um (außer wenn es nur für dich selbst ist)
 
Zuletzt bearbeitet:
Mit dieser simplen Methode, kann man sich schon mal die URL des Jar-Archives beliebiger Klassen holen:
Java:
public final class BaseURL {
	public static final URL getJarURL(Class<?> clazz) {
		URL rc = clazz.getResource(clazz.getSimpleName() + ".class");
		String name = clazz.getName().replace('.', '/').concat(".class");
		name = rc.toString().replace(name, "dummy");
		try {
			rc = new URL(null, name);
			return rc;
		} catch(MalformedURLException e) {
			return null;
		}
	}
}
Davon hat man zunächst erstmal zwar nichts, aber man kann die URL dann ja noch mal "redirecten":
Java:
public final class JarURLTest {
	public static void main(String ... args)
	{
		URL base = BaseURL.getJarURL(MyClass.class);
		try {
			base = new URL(base, "res");
		} catch(MalformedURLException r) {
			// ignore;
		}
	}
}
Schon kann man beliebige Ressourcen aus jedem erdenklichen Archiv laden, sofern man deren Pfad dort drin kennt.
@Mujahiddin: Du kommst auch mit "getRessource()" innerhalb eines Jars klar. "getRessource()" und "getRessourceAsStream()" sind dahingehend verschachtelt ("getRessource().openStream()"). Das Problem bei diesen Methoden ist, dass sie Pfad-Relativ arbeiten, deswegen fehlt einem öfters die Basis (BaseURL).
 
Zuletzt bearbeitet von einem Moderator:
Wie wuerdet ihr denn den Ordner nennen? In ihm soll per UNterordner Bilder, Info-Dateien und I18N-Dateien getrennt voneinander abgelegt werden. Und bisher hieß es, ich soll die in "res" packn.

Trotzdem danke fuer die Tipps - werde spaeter damit mal ein bisschen rumprobieren.

Thomas
 
Sorry, war ziemlich schlecht von mir gestern.
Ich hatte "user.dir" mit "user.home" verwechselt.
"res" ist schon gut, allerdings weiß ich persönlich nicht, ob "user.dir" immer das gewünschte Ergebnis liefert.
Falls du "res" innerhalb der .jar speichern willst, würde ich die Variante von Spacerat vorschlagen. Falls du aber "res" parallel zur .jar haben willst, wäre mein Vorschlag
Code:
new File("res");
.
 
So: Es wird in meinem Programm folgender Code ausgeführt:


Java:
public static void main(String[] args)
	{
		try
		{
			URL base = new URL (getJarURL(), "res");
			File f = new File(base.getPath(), "changeLog.html");
			BufferedReader br = new BufferedReader(new FileReader(f));
			String text = br.readLine();
			
			JOptionPane.showConfirmDialog(
					null,
					text,
					f.getPath(),
					JOptionPane.OK_OPTION);
		} catch (Exception e)
		{
			e.printStackTrace();
			
			JOptionPane.showMessageDialog(
					null,
					e.getMessage(),
					"Exception",
					JOptionPane.OK_OPTION);
		}
	}

Das Ergebnis ist der MessageDialog mit folgender Exception:

file:\E:\Documents\Programmierung\Eclipse\Runner\LoadFiles.jar!\res\changeLog.html (Die Syntax für den Dateinamen, Verzeichnisnamen oder die Datenträgerbezeichnung ist falsch)

Ich vermute mal, die URL wird falsch geladen in der Methode. Ich kann das leider nicht debuggen, weil in Eclipse ja nicht die Jar ausgeführt wird :S
Ich könnte theoretisch
Code:
String.substring()
benutzten und das ".jar!" entfernen, aber das keine bleibende Lösung finde ich. Vorallem weiß ich nicht, ob das funktioniert.

Was mache ich falsch?

Thomas

Edit: Hab jetzt per URL.getPath() und String.substring() einmal das Ausrufezeichen und beim zweiten Versuch das ".jar!" rausgefiltert, aber die Datei kann immer noch nicht gefunden werden :/

Thomas
 
Zuletzt bearbeitet:
Versuche mal:
Java:
public static void main(String[] args) {
	try {
		URL base = new URL( getJarURL(), "res/changeLog.html" );
		BufferedReader br = new BufferedReader( new InputStreamReader( base.openStream() ) );
		String text = br.readLine();
		
		JOptionPane.showConfirmDialog( null, text, base.getPath(), JOptionPane.OK_OPTION );
	} catch( Exception e ) {
		e.printStackTrace();
		
		JOptionPane.showMessageDialog( null, e.getMessage(), "Exception", JOptionPane.ERROR_MESSAGE );
	}
}

Übrigens muss bei showMessageDialog statt "OK_OPTION" ein "ERROR_MESSAGE" kommen, da ist nämlich nach messageType und nicht optionType gefragt.
 
Exception:

JAR entry res/changeLog.html not found in E:\Documents\Documents\Programmierung\Eclipse\Runner\LoadFiles.jar

Die Datei liegt zwar in dem Ordner res/ressource/, aber auch das funktioniert nicht.
 
Das liegt daran, das "getJarURL()" eine URL für das "jar"-Protokoll ("jar:file:/" statt nur "file:/") liefert mit welcher ausschliesslich Dateien aus diesem Archiv gelesen werden können.
Für Dateien ausserhalb eignet sich dann nur das gewohnte "new File(".").getAbsoluteFile().toUri().toURL();" für das aktuelle Verzeichnis, welches meines Erachtens für Resourcen auch am besten geeignet ist.
 
Aber ich will ja auch die Dateien aus dem jar-Archiv lesen. Deswegen ist das jar-Protokoll doch genau das richtige dafür.

edit: Wozu ist denn dieser "JAR entry" da, wenn ich damit keine Datei aus dem JAR-Archiv öffnen kann?
 
Zuletzt bearbeitet:
edit: Wozu ist denn dieser "JAR entry" da, wenn ich damit keine Datei aus dem JAR-Archiv öffnen kann?
Es gab mal Zeiten, da hab' ich mich das auch gefragt. Scheinbar gibts die Jar- bzw. ZipEntry nur, damit man innerhalb des Jars (Zips) zwischen Verzeichnis und Datei unterscheiden kann und um deren gepackte und ungepackte Länge festzustellen. Ich persönlich nutze die beiden Dinger nur noch, um sicherzustellen, dass "jarURL.openStream() nicht auf ein Verzeichnis oder nicht vorhandenen Eintrag ausgeführt wird.
 
Wie wäre denn jetzt der Code, um auf dieses Verzeichnis zuzugreifen:

E:\Documents\Documents\Programmierung\Eclipse\Runner\LoadFiles.jar\res\ressource\changeLog.html

oder für meine Bilder:

E:\Documents\Documents\Programmierung\Eclipse\Runner\LoadFiles.jar\res\images\cube.png


Nur so:
Jemand hat zuvor gesagt, dass man, wenn man im Root-Verzeichnis mit "getRessouce()" suchen will, ein Schrägstrich vor dem Dateipfad setzen soll. Tatsächlich sucht er immer in dem jeweiligen Package. Mit einem Schrägstrich geht er zurück in das bin-Verzeichnis. Aber weiter gehts auch nicht - sprich mit "getRessource()" geht das ganze von Anfang nicht. Habe es nämlich auch mal mit "/../res/images/cube.png" probiert, aber diese Art von Verzeichnis-Sprung kennt der nicht :/
 
Nächstes Problem:

Was in Eclipse funktioniert, ist in jar doch nochmal schwerer:

Bilder werden bisher wie folgt geladen:
Java:
	public static ImageIcon getIcon(String pathName, String descriptionKey)
	{
		ImageIcon tempIcon = new ImageIcon(BoxModell.class.getResource("/images/"
				+ pathName
				+ ".png"));
		tempIcon.setDescription(Languages.get(descriptionKey));
		return tempIcon;
	}

Das Problem, dass das ganze kopiert wird, lass ich jetzt mal außen vor. Mir gehts jetzt darum, dass das hier zwar funktioniert, aber wenn ich Text-Dateien per "FileReader" öffnen will, geht das nicht.
Das sieht nämlich so aus:

Java:
		try
		{
			URL url = BoxModell.class.getResource("/images/"
					+ "cube" + ".png");
			FileReader reader = new FileReader(new File(url.toURI())); // new FileReader(url.getPath());
			BufferedReader in = new BufferedReader(reader);
			String line = in.readLine();
			while (line != null)
			{
				changeLog += line;
				line = in.readLine();
			}
			in.close();
		} catch (Exception e)
		{
			e.printStackTrace();
		}

In dem Moment, wo der FileReader konstruiert werden soll, wird eine Exception geworfen. Das komische ist, die URL ist nicht null. Sie beginnt wie folgt:
"jar:file:E:\Documents\ [...]"
Der Pfad sollte stimmen (sonst wäre die URL gleich null). Kann der FileReader vll. nicht mit jar-Archiven umgehen?

Gruß, Thomas
 
Tschuldigt, dass ich jetzt dreimal hintereinander schreibe, aber ich Vollidiot hab noch nie in so eine jar-Datei geschaut.

Die Jar-Datei ist sozusagen das bin-Verzeichnis verpackt. Da wird res gar nicht mitgepackt -> Ich muss res als Package in "src" lagern, damit es auch in bin liegt.

Das Problem mit der Textdatei (siehe letzter Post) ist aber immer noch ungelöst.
 
Kann der FileReader vll. nicht mit jar-Archiven umgehen?
Ganz genau, das kann er nicht. Ebensowenig sollte man versuchen aus "jar"-Protokollen (oder allen anderen ausser "file") "file"-Protokolle zu machen (z.B. mit "new File(url.getFile()).toURI().toURL()" o.ä), das schlägt fehl.
Die meisten URLs haben sehr wenig mit dem File-Protokoll zu tun, deswegen gibt es ja die Methode "openStream()". Wenn du also einen Text-Reader brauchst bekommst du ihn nur so:
Java:
Reader reader = new InputStreamReader(url.openStream());
Natürlich lassen sich Streams und Reader/Writer in Java immer noch schachteln, so dass nun auch ein BufferedReader kein Problem mehr darstellen sollte.
 
Zuletzt bearbeitet von einem Moderator:
So, das hat jetzt super geklappt. Die Idee von einem Resourcen-Ordner ist jetzt einfach zu einem extra Package "res" geworden und das mit hab ich auch alles.

Vielen Dank für die Hilfe 🙂

Thomas
 
Wenn du in deinem Projekt in Eclipse einen neuen "Source Folder" mit dem Namen "res" erstellst, geht es auch. Er sollte das auch in die "bin", also ins jar, packen.
In diesem musst du dann zwar auch ein package "res" erstellen (also in deinem Explorer ist das dann res/res), aber sieht meiner Meinung viel besser aus als src/res!
 

Neue Themen


Zurück
Oben