# Korrekte Pfadangaben damit eine .jar Datei unter Windwos läuft.



## snuff (13. Jun 2017)

Hallo zusammen

Ich habe ein Programm geschrieben und möchte dies nun als executable jar file speichern und nutzen. Das Problem ist, dass die .jar Datei bei einem Doppelklick nicht startet. (keine Fehlermeldung oder Ähnlichens)

In der Entwicklungsumgebung funktioniert das Programm einwandfrei. Wenn ich die .jar Datei via cmd starte sehe ich, dass das Programm immer dort eine NullPointerException wirft, wo mit Pfaden gearbeitet wird, z.B. beim Laden von Bildern oder beim Speichern von Dateien.

Alle Daten sind im jar file selbst abgelegt. Die Pfade sind relativ zum Projektverzeichnis.
Wenn ich das soweit richtig verstanden habe muss unter Windows die Pfadangabe so erfolgen:

```
src\\name\\nochEinName\\usw...
```

Gibt es sonst noch was zu beachten damit das .jar file funktioniert? Weshalb mir die Konsole eine NullPointerExcepttion an dieser Stelle ausgibt ist mir auch nicht schlüssig, zumal ich eher eine FileNotFoundException erwarten würde.


----------



## VfL_Freak (13. Jun 2017)

Moin,

poste doch wenigstens den StackTrace sowie den zugehörigen Code ... 

VG Klaus


----------



## snuff (13. Jun 2017)

Beispiel:
Eine Klasse speicher in einem Ordner namens "save" Dateien. Beim Programmstart wird überprüft welche Dateien schon vorhanden sind. Folgender Code gibt mir ein String Array mit den Dateinamen:


```
File folder = new File("src\\MyProgram\\userinterface\\save\\");
        File[] listOfFiles = folder.listFiles();
        String[] fileNames = new String[listOfFiles.length]; //Das ist Zeile 194
```

Die cmd gibt mit diese Meldung:


----------



## Thallius (13. Jun 2017)

Das kann nicht gehen da es diesen Ordner natürlich nicht gibt. Und in das .jar File kannst du sowieso nicht schreiben. Du must dir also eine andere Lösung suchen.

Gruß

Claus


----------



## snuff (13. Jun 2017)

Weiteres beispiel:

Beim Laden von Icons.
Mit dieser Methode werden Icons geladen:

```
public static ImageIcon loadIcon(String strBild) {
        MediaTracker tracker = new MediaTracker(p);
        ImageIcon icon = new ImageIcon(Utility.class.getResource("..\\images\\icons\\" + strBild)); //das ist Linie 52
        tracker.addImage(icon.getImage(), 0);
        try {
            tracker.waitForID(0);
        } catch (InterruptedException ex) {
            System.out.println("Fehler beim Laden.");
        }
        return icon;
    }
```

Danach soll ein MenuItem ein Icon laden:

```
JMenuItem menuItem = new JMenuItem("Help",Utility.loadResourceIcon("blueIcons\\16x16\\help.png")); //das ist Linie 87
```

Worauf mit die cmd folgendes gibt:



image hosting


----------



## Thallius (13. Jun 2017)

Zuncähst mal würde ich mir angewöhnen File.separator zu benutzen. Das macht das Leben deutlich einfacher wenn dein Programm auch mal unter Linux oder Mac laufen soll. Diese ollen Backslashes von Windows sind nämlich ziemlich überholt.

Die Pfadangabe ist auf jeden Fall Mist da .. am Anfang bedeutet, dass er eine Ebene nach oben gehen soll. Das aus dem .jar heraus kann wieder nicht funktionieren da das .jar in dem Moment nunmal das root ist. Mich würde es sogar nicht einmal wundern wenn die Dateien gar nicht in deinem jar drin sind. Hast Du da mal reingesehen?


----------



## snuff (13. Jun 2017)

> Das kann nicht gehen da es diesen Ordner natürlich nicht gibt. .


Warum sollte es den nicht geben?



> Und in das .jar File kannst du sowieso nicht schreiben.


Sehr gut zu wissen!


----------



## snuff (13. Jun 2017)

> Das aus dem .jar heraus kann wieder nicht funktionieren da das .jar in dem Moment nunmal das root ist.



Wie würde man dann im jar file korrekt referenzieren? Die Bilder sind in einem Ordner namens "images", dieser wiederum ist eine Ebene höher als die ganzen .java Dateien.



> Hast Du da mal reingesehen?



Wenn cih das jar file z.B. mit 7Zip öffne dann sind da alle Bilder zu sehen, also ja.


----------



## mrBrown (13. Jun 2017)

Thallius hat gesagt.:


> Zuncähst mal würde ich mir angewöhnen File.separator zu benutzen. Das macht das Leben deutlich einfacher wenn dein Programm auch mal unter Linux oder Mac laufen soll. Diese ollen Backslashes von Windows sind nämlich ziemlich überholt.


`File.separator` ist Unsinn, das ist genauso überholt. Einfach '/' benutzen.



Thallius hat gesagt.:


> Die Pfadangabe ist auf jeden Fall Mist da .. am Anfang bedeutet, dass er eine Ebene nach oben gehen soll. Das aus dem .jar heraus kann wieder nicht funktionieren da das .jar in dem Moment nunmal das root ist. Mich würde es sogar nicht einmal wundern wenn die Dateien gar nicht in deinem jar drin sind. Hast Du da mal reingesehen?


in getResource bedeutet das, aus dem aktuellem package eins hoch wechseln.



snuff hat gesagt.:


> Wie würde man dann im jar file korrekt referenzieren? Die Bilder sind in einem Ordner namens "images", dieser wiederum ist eine Ebene höher als die ganzen .java Dateien.


Zeig einmal deine genaue Ordnerstruktur. Prinzipiell müsste `getResource("../images/icons/" + strBild))` passend sein


----------



## snuff (13. Jun 2017)

Hallo

Danke für die schnellen Antworten

Die Ordnerstruktur sieht wie folgt aus:




Entschuldigt die schreckliche Visualisierung aber ich weiss gerade nicht wie ich auf die schnelle eine Ordnerstruktur schön darstellen kann.


----------



## mrBrown (13. Jun 2017)

`class.getResource("/images/icons/" + strBild))` dürfte funktionieren, die Variante mit '../' allerdings auch


----------



## snuff (13. Jun 2017)

```
class.getResource("/images/icons/" + strBild))
```
  führt zur Exception


```
class.getResource("../images/icons/" + strBild))
```
 Funktioniert in der Entwicklungsumgebung, führt als .jar File zur Exception beim Aufruf von:

```
JMenuItem menuItem = new JMenuItem("Help",Utility.loadIcon("blueIcons/16x16/help2.png"));
```


----------



## mrBrown (13. Jun 2017)

In welchem Package liegt deine Utility?


----------



## snuff (13. Jun 2017)

Die Utilita liegt im package MyProgram.tools
Alle anderen java Dateien sind in MyProgram.userinterface


----------



## mrBrown (13. Jun 2017)

Ahh, dann `class.getResource("/MyProgram/images/icons/" + strBild))`

BTW, packages schreibt man klein


----------



## snuff (13. Jun 2017)

Sry ich bin noch absoluter Programmier-Anfänger und kenne noch viele Teile der Java-Wicht.


```
class.getResource("/MyProgram/images/icons/" + strBild))
```
führt zur Exception.

 Utility.class.getResource()liefert mir doch einen relativen Ressourcennamen, die Utility ist wiederum eine Ebene Tiefer (MyProgram.tools). Kann dann dieser Pfad überhaupt stimmen?

Kann man Pfade evt relativ zum Root-Verzeichnis des Projektes setzten? Falls ja was ist das Root-Verzeichnis? "MyProgram"? "src"?


----------



## mrBrown (13. Jun 2017)

MyProgram mit einem oder mit zwei 'm'?


Den Root (=src) erreichst du mit einem '/' am Anfang


----------



## snuff (13. Jun 2017)

Also wir kommen der Sache schon deutlich näher.


```
class.getResource("/MyProgram/images/icons/" + strBild))
```
Funktioniert. Die Exception wurde geworfen weil beim Aufruf noch ein "falscher" "\\" mitgegeben wurden.
Ich bin nun durchs ganze Programm gegangen und habe alle Dopper-Backslashes wieder durch normale Slashes ersetzt. Das .jar File lässt sich nun sogar starten.

Schon mal vielen Dank!

Allerdings gibt es noch Kleinigkeiten bei denen ich den Fehler noch nicht sehe.


```
menuItem = new JMenuItem("Help",Utility.loadIcon("blueIcons/16x16/help2.png"));
```
funktioniert Problemlos.


Hingegen wirft folgendes eine Exception.

```
btInfo = new JButton("Info",Utility.loadIcon("blueIcons/24x24/info2.png"))
```

Der JButton funktioniert in der Entwicklungsumgebung, aber in der .jar file nicht. Wenn ich das jar file mit 7Zip öffne sind beide Verzeichnisse sowie Dateien da.

In der Konsole wird wieder beim Versuch diesen JButton zu instanzieren eine NullPointerException von der Utility geworfen.


----------



## snuff (13. Jun 2017)

Noch eine Ergänzung.

Wie Oben erwähnt speichert das Programm auch Daten ab. Und wie ich ebenfalls erfahren habe können keine Dateien in das jar file geschrieben werden.

Ich habe das so gelöst dass der Benutzer zuerst via JFileChooser einen Pfad wählen muss und die Dateien dann dort gespeichert und geladen werden. Das funktioniert so weit ohne Probleme.

Jetzt möchte ich aber auch Dateien laden können, welche sich im jar file befinden. (Nur laden, nicht Speichern. Es handelt sich dabei um Default-Werte des Programmes welche geladen werden sollen)

Auch hier wirft mir Java eine Exception wenn ich diese Datei aus dem jar file laden möchte.
Die Dateien sind in src/MyProgram/userinterface/save abgelegt. Die dazugehörige Klasse ist in src/MyProgram/userinterface 

Im Moment werden die Dateien noch so geholt:

```
importFile = new FileInputStream("src/MyProgram/userinterface/save/Default.ser");
```

Das Funktioniert in der Entwicklungsumgebung aber nicht im -jar File. Wie bekomme ich dort den korrekten Pfad?


----------



## mrBrown (13. Jun 2017)

snuff hat gesagt.:


> Allerdings gibt es noch Kleinigkeiten bei denen ich den Fehler noch nicht sehe.


Da seh ich den Fehler auch nicht - Icon falsch benannt oä?



snuff hat gesagt.:


> Das Funktioniert in der Entwicklungsumgebung aber nicht im -jar File. Wie bekomme ich dort den korrekten Pfad?


class.getResourceAsStream ist der Trick


----------



## snuff (13. Jun 2017)

Wie wird das genau implementiert?

```
importFile = class.getResourceAsStream(...)
importFile =  (FileInputStream) this.getClass().getResourceAsStream(...);
```

ersteres geht gar nicht und zweiteres akzeptiert der Compiler, aber beim Ausführen kommt eine CastException (BufferedInputStream zu FileInputStream)


----------



## mrBrown (13. Jun 2017)

Ja, die Methode gibt dir keinen FileInputStream zurück, sondern einen InputStream. Änder deine Nutzung von FileInputStream zu InputStream und das klappt


----------



## snuff (13. Jun 2017)

Tatsächlich funktioniert einwandfrei 

Danke!


----------



## Thallius (13. Jun 2017)

mrBrown hat gesagt.:


> `File.separator` ist Unsinn, das ist genauso überholt. Einfach '/' benutzen.



Seit wann ist es Unsinn einen OS unabhängigen Define zu benutzen? Mag ja sein, dass Windows mittlerweile schlau genug ist das es auch / versteht aber dann kommt einer und lässt es auf einem anderen Betriebssystem, das Du vielleicht gar nicht kennst , laufen und das # als Separator benutzt und schon ist dein / fürn Ar.....

Claus


----------



## mrBrown (13. Jun 2017)

Thallius hat gesagt.:


> Seit wann ist es Unsinn einen OS unabhängigen Define zu benutzen? Mag ja sein, dass Windows mittlerweile schlau genug ist das es auch / versteht aber dann kommt einer und lässt es auf einem anderen Betriebssystem, das Du vielleicht gar nicht kennst , laufen und das # als Separator benutzt und schon ist dein / fürn Ar.....


Mag überraschend für dich sein, aber Java händelt sowas für dich  Völlig egal was das OS als Separator benutzt, '/' ist für Pfade der richtige Separator.

In class.getResource dürfte '\' btw zu Fehlern führen - im Gegensatz zu '/'


----------

