ubuntuusers.de

[Java] Pfadangaben von Resourcen in jar Dateien

Status: Gelöst | Ubuntu-Version: Ubuntu 7.10 (Gutsy Gibbon)
Antworten |

Quidoff

Avatar von Quidoff

Anmeldungsdatum:
2. Juni 2006

Beiträge: 445

Wohnort: Jossgrund

Hallo,
ich wollte gerade ein Java-Programm in eine jar-Datei auslagern, habe aber das Problem, dass
dieses Programm eine Ressourcendatei laden muss (genauer gesagt eine xml-Datei), die in einem
Unterordner "data" des Stammverzeichnisses liegt.
Innerhalb des Codes wird die Datei einfach durch "data/simple.xml" geladen, wenn das Programm
aber (mit "data"-Verzeichnis) in eine jar-Datei ausgelagert wird, dann wird nach der Datei im
Verzeichnis, in dem java ausgeführt wird, gesucht. Wie kann ich den Code dahingegen ändern, dass
die Ressourcendatei innerhalb des jar-Archivs gesucht wird, falls sie sich in einer jar-Datei befindet,
oder innerhalb des Stammverzeichnisses, falls das Programm als entpackt ausgeführt wird.
Wäre schön, wenn es eine Lösung gäbe, bei denen man zwischen dieses Fällen nicht
unterscheiden muss. Das die Lösung also sowohl bei den entpackten Sourcen, als auch in einem
jar-Archiv funktioniert.

Mein zweites Problem ist, dass ich innerhalb des Programms auf Klassen zugreife, die in einem
anderen externen jar-Archiv liegen. Auf diese habe ich anscheinend keinen Zugriff mehr,
wenn ich das Programm in eine jar-Datei auslagere. Jedenfalls bekomme ich auch dann noch einen
java.lang.NoClassDefFoundError Fehler, wenn ich die externe jar-Datei per -cp an den classpath
anhänge.

Dawnrazor

Avatar von Dawnrazor

Anmeldungsdatum:
23. August 2006

Beiträge: 883

Wohnort: Dortmund

z.B so

private BufferedImage loadPics(String path)
  {
    BufferedImage source = null;

    URL pic_url = getClass().getClassLoader().getResource(path);

    try
    {
      source = ImageIO.read(pic_url);
    }
    catch (IOException e)
    {
      e.printStackTrace();
    }
    return source;
  } 

Der Aufruf:

BufferedImage wuerfel = this.loadPics("pics/beispiel.gif");

wenns ein font ist:

font = Font.createFont(Font.TRUETYPE_FONT, getClass().getClassLoader().getResourceAsStream("pics/ARIAL.TTF"));

Im Anhang hast du ein Beispiel, wie das unter Eclipse aussehen muss

Bilder

Quidoff

(Themenstarter)
Avatar von Quidoff

Anmeldungsdatum:
2. Juni 2006

Beiträge: 445

Wohnort: Jossgrund

Danke für die Antwort.
Ich bin inzwischen auf eine ähnliche (halb funktionierende Lösung gekommen)

Zuerst wundert es mich, dass du den Ressourcen-Ordner nicht in den bin-Ordner schieben musst.
Das musste ich nämlich bei meiner Lösung, die folgendermaßen aussieht.

String pfad = "data/";
URL url = this.getClass().getClassLoader().getResource(pfad + "simple.glade");
if(url==null) System.out.println("url is null");


Die xml-Datei, die ich laden will, ist also simple.glade und befindet sich im Ordner data, welcher sich im Ordner bin befindet.

Dieser Code funktioniert in Eclipse wunderbar, nicht aber, wenn ich das Programm in eine jar packe:

$ java -Djava.library.path=/usr/lib -jar Glade.jar 
Exception in thread "main" java.io.FileNotFoundException: 
Can't find the specified Glade XML file:
/home/korn/Desktop/file:/home/korn/Desktop/Glade.jar!/data/simple.glade
        at org.gnome.glade.Glade.parse(Glade.java:142)
        at org.testing.Simple.<init>(Simple.java:25)
        at org.testing.Simple.main(Simple.java:49)


Die jar Datei scheint aber richtig aufgebaut zu sein.

$ unzip -l Glade.jar | grep -v gnome | grep -v freedesktop
Archive:  Glade.jar
  Length     Date   Time    Name
 --------    ----   ----    ----
       71  02-23-08 12:15   META-INF/MANIFEST.MF
        0  02-23-08 11:38   org/
        0  02-23-08 11:38   org/testing/
     1275  02-23-08 11:41   org/testing/Simple.java
    18620  02-23-08 04:23   typeMapping.properties
      572  02-23-08 08:20   .classpath
      364  02-22-08 01:51   .project
        0  02-23-08 11:39   data/
     1949  02-23-08 06:29   data/simple.glade
     3427  02-23-08 03:51   data/simple.glade.bak
      273  02-23-08 03:51   data/simple.gladep
      273  02-23-08 03:51   data/simple.gladep.bak
      786  02-23-08 11:41   org/testing/Simple$1.class
      944  02-23-08 11:41   org/testing/Simple$2.class
     2442  02-23-08 11:41   org/testing/Simple.class
 --------                   -------
  2345257                   1707 files

Das Manifest sieht so aus:

Manifest-Version: 1.0
Sealed: true
Main-Class: org.testing.Simple


Wobei ich mir der Bedeutung von Sealed noch nicht ganz bewusst bin.

(Wo ich zu meiner anderen Frage komme. Ich benutze in meinem Programm eine Klasse, die in einer
anderen jar Datei deklariert ist. Ich habe diese jar Datei entpackt und zu meinem Programm hinzugefügt,
wodurch mein Programm einen ziemlichen Overhead bekommt, wie man an der Anzahl der Dateien sehen kann.)

Dawnrazor

Avatar von Dawnrazor

Anmeldungsdatum:
23. August 2006

Beiträge: 883

Wohnort: Dortmund

hast du den ordner "data" in eclipse als source ordner angelegt?

rechtsklick auf das Project → new → source Folder → resources → da schiebste dann deine Ordner rein

P.S. der pics ordner wird beim compilieren automatisch in bin geschrieben

Quidoff

(Themenstarter)
Avatar von Quidoff

Anmeldungsdatum:
2. Juni 2006

Beiträge: 445

Wohnort: Jossgrund

Ok. Danke. Ich wusste nicht, dass ich noch einen Ordner über data brauche.

Da die resultierende jar-Datei aber die gleiche ist, bleibt der Fehler bestehen.

Dawnrazor

Avatar von Dawnrazor

Anmeldungsdatum:
23. August 2006

Beiträge: 883

Wohnort: Dortmund

klappt es so?

URL url = this.getClass().getClassLoader().getResource("data/simple.glade");

Quidoff

(Themenstarter)
Avatar von Quidoff

Anmeldungsdatum:
2. Juni 2006

Beiträge: 445

Wohnort: Jossgrund

Wo ist der Unterschied zu:
String pfad = "data/";
URL url = this.getClass().getClassLoader().getResource(pfad + "simple.glade");

???

Dawnrazor

Avatar von Dawnrazor

Anmeldungsdatum:
23. August 2006

Beiträge: 883

Wohnort: Dortmund

upps

habe das String pfad = "data/"; überlesen ☹

Wie bildest du die jar denn?

Quidoff

(Themenstarter)
Avatar von Quidoff

Anmeldungsdatum:
2. Juni 2006

Beiträge: 445

Wohnort: Jossgrund

Bin glaube ich der Lösung etwas näher gekommen.
Zum einen ist mir aufgefallen, dass bei der Ausgabe der Pfad zweimal auftaucht.
Ich habe deshalb in Eclipse [ ] Add directory entries deaktiviert.

Das ist mein Code:

URL url = this.getClass().getClassLoader().getResource("/data/simple.glade");

Ich erhalte sowohl in Eclipse als auch mit der jar die Ausgabe:

url is null
Exception in thread "main" java.lang.NullPointerException
        at org.testing.Simple.<init>(Simple.java:24)
        at org.testing.Simple.main(Simple.java:48)

Wenn ich den Code so ändere, dass ich das führende / entferne, dann läuft das Programm in Eclipse, aber die Ausgabe der jar in der Konsole bringt:

$ java -Djava.library.path=/usr/lib -jar Glade.jar
Exception in thread "main" java.io.FileNotFoundException: 
Can't find the specified Glade XML file:
/home/korn/Desktop/file:/home/korn/Desktop/Glade.jar!/data/simple.glade
        at org.gnome.glade.Glade.parse(Glade.java:142)
        at org.testing.Simple.<init>(Simple.java:24)
        at org.testing.Simple.main(Simple.java:48)

Meine Verzeichnisstruktur sieht so aus:

Ungültiges Makro

Dieses Makro ist nicht verfügbar

Die jar sieht so aus:

$ unzip -l Glade.jar | grep -v gnome | grep -v freedesktop
Archive:  Glade.jar
  Length     Date   Time    Name
 --------    ----   ----    ----
       57  02-23-08 14:14   META-INF/MANIFEST.MF
      786  02-23-08 14:13   org/testing/Simple$1.class
      944  02-23-08 14:13   org/testing/Simple$2.class
     2183  02-23-08 14:13   org/testing/Simple.class
     1949  02-23-08 06:29   data/simple.glade
     3427  02-23-08 03:51   data/simple.glade.bak
      273  02-23-08 03:51   data/simple.gladep
      273  02-23-08 03:51   data/simple.gladep.bak
    18620  02-23-08 04:23   typeMapping.properties
      619  02-23-08 13:21   .classpath
      364  02-22-08 01:51   .project
 --------                   -------
  2343756                   1691 files

Das Manifest so:

Manifest-Version: 1.0
Main-Class: org.testing.Simple

Dawnrazor

Avatar von Dawnrazor

Anmeldungsdatum:
23. August 2006

Beiträge: 883

Wohnort: Dortmund

nun soweit ich das erkennen kann, hast du nun alles korrekt gemacht

hat es evtl. was mit der Dateiberechtigung zu tun?

Sorry, aber ab nun muss ich leider passen ☹

Quidoff

(Themenstarter)
Avatar von Quidoff

Anmeldungsdatum:
2. Juni 2006

Beiträge: 445

Wohnort: Jossgrund

Kann ich mir nicht vorstellen.
Es wird kein Befehl als root ausgeführt.

Möglicherweiße habe ich die notwendigen Informationen nur noch nicht gepostet:
.project:

<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
	<name>Glade</name>
	<comment></comment>
	<projects>
	</projects>
	<buildSpec>
		<buildCommand>
			<name>org.eclipse.jdt.core.javabuilder</name>
			<arguments>
			</arguments>
		</buildCommand>
	</buildSpec>
	<natures>
		<nature>org.eclipse.jdt.core.javanature</nature>
	</natures>
</projectDescription>

.classpath

<?xml version="1.0" encoding="UTF-8"?>
<classpath>
	<classpathentry kind="src" path="src">
		<attributes>
			<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="/usr/lib/jni/"/>
		</attributes>
	</classpathentry>
	<classpathentry kind="src" path="resources"/>
	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
	<classpathentry kind="lib" path="glade">
		<attributes>
			<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="/usr/lib"/>
		</attributes>
	</classpathentry>
	<classpathentry kind="output" path="bin"/>
</classpath>

Mehr Informationen zum Posten fallen mir auch nicht mehr ein.

Quidoff

(Themenstarter)
Avatar von Quidoff

Anmeldungsdatum:
2. Juni 2006

Beiträge: 445

Wohnort: Jossgrund

Da ich gar keine Idee mehr habe, habe ich den Code mal hochgeladen.
Wäre nett, wenn es jemand in eine lauffähige jar-Datei packen könnte und dann
hier posten könnte, wo der Fehler war und wie man ihn behebt.
Glade.rar
libgtkjni-4.0.so (Muss als native library des Projekts eingetragen werden)
Ausführung der jar Datei dann mit: java -Djava.library.path=/usr/lib -jar Glade.jar (/usr/lib zum Pfad ändern, in dem die Datei liegt)

Quidoff

(Themenstarter)
Avatar von Quidoff

Anmeldungsdatum:
2. Juni 2006

Beiträge: 445

Wohnort: Jossgrund

Also es ist wohl nicht möglich einen Pfad zu einer Resource innerhalb einer jar-Datei anzugeben. Es liese sich wohl ein File Objekt erstellen, aber damit kann der Konstruktor nicht umgehen, weshalb noch die Möglichkeit bleibt, eine lokale Kopie zu erstellen.

Quidoff

(Themenstarter)
Avatar von Quidoff

Anmeldungsdatum:
2. Juni 2006

Beiträge: 445

Wohnort: Jossgrund

So, wie gesagt, musste die temporäre Kopie des xml-Skripts erzeugt werden:

private void loadGUIFile() throws IOException {
		f = File.createTempFile("simple", "glade");
		InputStream is = this.getClass().getResourceAsStream("/data/simple.glade");
		FileOutputStream os = new FileOutputStream(f);

		byte by;

		while ((by = (byte) is.read()) != -1) {
			os.write(by);
		}
		f.deleteOnExit();
		os.close();
	} 
Antworten |