*.jar öffnet PDF-Datei nicht

Jacl

Aktives Mitglied
Ich möchte eine Hilfedatei im PDF-Format wenn auf ein Bild mit der Maus geklickt wird öffnen – das Bild wurde in ein JLabel integriert (siehe Codeschnipsel).
In der IDE (Netbeans) funktioniert es wunderbar. Wenn ich jedoch eine *.jar erstelle und diese dann starte zeigt das Standard PDF-Programm folgendes an:
Code:
Dokument »file:///tmp/Hilfe9050727549084865621.pdf« konnte nicht geöffnet werden.
PDF document is damaged
Ich würde das ganze gerne "plattformunabhängig" hinbekommen!
Java:
if (Desktop.isDesktopSupported()) {
                    try {
                        InputStream is = getClass().getResourceAsStream("Hilfe.pdf");
                        byte[] data = new byte[is.available()];
                        is.read(data);
                        is.close();
                        String tempFile = "Hilfe";
                        File temp = File.createTempFile(tempFile, ".pdf");
                        FileOutputStream fos = new FileOutputStream(temp);
                        fos.write(data);
                        fos.flush();
                        fos.close();
                        Desktop.getDesktop().open(temp);
                    } catch (IOException ex) {
                    ex.printStackTrace();
                    }
                }

Was mache ich falsch, kann mir wer helfen?
 
Das Problem ist die Art und Weise, wie du InputStream.read(byte[]) verwendest, um die Bytes aus der Datei zu lesen.
Reads some number of bytes from the input stream and stores them into the buffer array b. The number of bytes actually read is returned as an integer. ...
Heißt: Du solltest in einer Schleife solange InputStream.read() aufrufen, bis diese Methode -1 zurückliefert und jeweils den Rückgabewert benutzen, um die tatsächlich gelesenen Bytes in den FileOutputStream zu schreiben, vorzugsweise mittels FileOutputStream.write(byte[], int, int).

Auch liefert InputStream.available() nicht die tatsächliche Anzahl der Bytes, die der Stream potentiell zurückliefern kann:
Returns an estimate of the number of bytes that can be read (or skipped over) from this input stream without blocking by the next invocation of a method for this input stream.
 
Gibt's hierfür irgendwo ein Codeschnipsel das ich anpassen kann? Das mit dem InputStream.read() kriege ich hin:
Java:
try {
   InputStream inputstream = new FileInputStream("Hilfe.pdf");
   int data = inputstream.read();
   while(data != -1) {
      data = inputstream.read();
   }
   inputstream.close();
Zumindest glaube ich das es so funktioniert. Aber bei der Ausgabe mit FileOutputStream.write(byte[], int, int) stehe ich an!
 
Du solltest schon weiterhin InputStream.read(byte[]) verwenden. Das füllt ja im übergebenen byte[]-Array Bytes, von vorne beginnend, und liefert die Anzahl der geschriebenen/gefüllten Bytes als Rückgabewert. Jetzt dann halt einfach diesen Rückgabewert für `len` in FileOutputStream.write(byte[], int, int) verwenden, zusammen mit dem byte[]-Array.
Du brauchst also trotzdem noch ein byte[] Array als Puffer für die Effizienz. Kannst das irgendwie dimensionieren, z.B. 8192 Bytes.
 
Also ich habe nun folgendes funktionierendes Konstrukt erstellt bei dem die *.jar Datei die PDF.Hilfedatei lädt. Ob's auch auf anderen Systemen läuft kann ich erst am Montag feststellen - unter Linux läuft es:
Java:
InputStream inputStream = this.getClass().getResourceAsStream("Hilfe.pdf");
File tempOutputFile = null;
try {
    tempOutputFile = File.createTempFile( "Hilfe", "pdf" ); // oder in ein Anwendungsverzeichnis!?
    } catch (IOException ex) {
            Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
        }
        tempOutputFile.deleteOnExit(); // löscht die Datei wieder, wenn die Anwendung geschlossen wird
        FileOutputStream out = null;
        try {
            out = new FileOutputStream( tempOutputFile );
        } catch (FileNotFoundException ex) {
            Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
        }
        byte buffer[] = new byte[ 8192 ];
        int len;
        try {
        while( ( len = inputStream.read( buffer ) ) > 0 ) {
            out.write( buffer, 0, len );
        }
        } catch (IOException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            out.close();
        } catch (IOException ex) {
            Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            inputStream.close();
        } catch (IOException ex) {
            Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            Desktop.getDesktop().open(tempOutputFile);
        } catch (IOException ex) {
            Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
        }
Ein Anfänger halt - aber im Moment funktioniert es, ob systemübergreifend wird sich zeigen...
Vielen Dank jedenfalls für die Hilfe
 
Zuletzt bearbeitet:
Du brauchst das try-catch nicht um jedes Statement einzeln machen. Mit try-with-resources wirds noch schöner, weil man sich um das Schließen nicht mehr zu kümmern braucht. Dann kann man das ganze noch in ein paar Methoden packen.

Mal ein paar Impulse (alles ungetestet):

Java:
private Optional<File> helpFile = Optional.empty();

public void showHelp() {
    try {
        createHelpFileIfNeccessary();
        Desktop.getDesktop().open(helpFile.get());
    } catch (IOException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    }
}

private void createHelpFileIfNeccessary() throws IOException {
    if (helpFile.isPresent()) {
        return;
    }

    File pdfFile = File.createTempFile("Hilfe", "pdf");
    pdfFile.deleteOnExit();
    saveResourceTo(pdfFile, "Hilfe.pdf");
    helpFile = Optional.of(pdfFile);
}

void saveResourceTo(File dest, String resource) throws IOException {
    try(InputStream in = getClass().getResourceAsStream(resource);
            FileOutputStream out = new FileOutputStream(dest)) {
        transfer(in, out);
    }
}

Die Methode transfer ist als Platzhalter zu verstehen. Ab Java 9 kann man direkt is.transferTo(out); aufrufen. In früheren Versionen macht man es halt so, wie Du es gemacht hast:
Java:
void transfer(InputStream is, OutputStream os) throws IOException {
    byte[] buf = new byte[8192];
    int n;
    while ((n = is.read(buf)) != -1) {
        os.write(buf, 0, n);
    }
}
 
Hallo, bin wieder mit einer Frage zu diesem Thema hier. Hat alles wunderbar mit den oben angeführten Tipps funktioniert - allerdings nur unter Linux. Wenn ich das Test.jar unter Windows starte, wird meine Hilfe.pdf aus dem Test.jar nicht geladen. Es gibt auch keine Fehlermeldung oder sonstwas. Die Hilfe.pdf liegt innerhalb der Jar-Datei im selben Verzeichnis wie die Test.class es gibt keine anderen Verzeichnisse/Ordner, nur eine einzige Ebene in der alles drinnen ist! Daher steht auch nur "Hilfe.pdf" und kein "/" oder "\" oder ein Pfad:
Java:
InputStream inputStream = this.getClass().getResourceAsStream("Hilfe.pdf");
Hat hierbei jemand Erfahrung - woran kann das liegen, dass es unter Windows 7 plötzlich nicht geht? 🙁 Wie gesagt, unter Linux ist es perfekt...
Jacl
 
sollte sich dann aber unter Windows und Linux identisch verhalten, /Hilfe.pdf und Hilfe.pdf werden aus
dem Default-Package heraus ja gleich aufgelöst.
Ja, darum habe ich die Doku zu Class-HTML auch nochmal angesehen und bin dann mit dem modified package name durcheinander gekommen.

Einzige Erklärung, die mir dazu einfällt ist die, auf die Du oben hinaus wolltest: das PDF ist im jar nicht enthalten und liegt auf seinem Linux-System zufällig im Classpath an der betreffenden Stelle.
 
Einzige Erklärung, die mir dazu einfällt ist die, auf die Du oben hinaus wolltest: das PDF ist im jar nicht enthalten und liegt auf seinem Linux-System zufällig im Classpath an der betreffenden Stelle.
Wäre zumindest aktuell die einzige Erklärung, die mir einfällt - sollte dann aber auch 'nen Fehler geben.
Der Fall, dass es unter Windows funktioniert und beim Wechsel nicht mehr hätte mehr Erklärungsmöglichkeiten...
 
Probier mal "/Hilfe.pdf"
Führt unter Linux bereits beim Ausführen in der IDE zu einem Fehler.
Einzige Erklärung, die mir dazu einfällt ist die, auf die Du oben hinaus wolltest: das PDF ist im jar nicht enthalten und liegt auf seinem Linux-System zufällig im Classpath an der betreffenden Stelle.
Nein, die Hilfe.pdf ist definitiv im Jar enthalten, ich hab's mir angesehen.
Ich kann's mir noch nicht erklären, aber möglicherweise hängt es mit dem addMouseListener zusammen
Java:
addMouseListener(new MouseAdapter() {
    @Override
    public void mouseClicked(MouseEvent e) {
      //TODO
    }
});
Der hängt nämlich an einem JLabel mit Bild, das beim anklicken eben die Hilfe.pdf öffnen soll. Und unter Windows muss der Listener irgendwie anderns an's JLabel angehängt werden, möglicherweise...
Ich kann das immer nur am Abend ändern und am nächsten Tag in der Arbeit ausprobieren. Der Inhalt meiner Jar:
Verzeichnisse: META-INF und Test. Nachdem öffnen des Ordners Test steht folgender Inhalt:
Code:
0000ff.gif, Hilfe.pdf, Test$1.class, Test$2.class, Test$3$1.class, Test$3.class, Test$4.class,Test$5.class, Test$6.class, Test$7.class, Test$8.class Test.class.
 
Zuletzt bearbeitet:
OK, schau Deinen Code durch, ob Du irgendwo Exceptions abfängst und ignorierst/nicht ausgibst. Falls das zu keinem Ergebnis führt, würde ich einfach mal in den Methoden, die am Aufruf beteiligt sind, Debugging-Ausgaben reinhauen und schauen, wo es hängt.
 
Moment - woher weißt du eigentlich, dass die PDF nicht geladen wird, wenn es keine Ausgabe dazu gibt?
Weil die Datei Hilfe.pdf nicht geöffnet wird und im Programmmanager (hätte sich was im Hintergrund getan) auch nix ersichtlich ist. Wenn man auf's Bild mit dem Listener klickt tut sich überhaupt nix (wie wenn kein Listener vorhanden ist)! Ich habe nun die ganze Woche probiert, den Listener einmal auf ein JLabel mit und ohne Bild zu legen, dann habe ich's mit einem Button probiert - leider alles erfolglos. Ich bin mit meinem Latein am Ende. Mit meinem jetztigen Wissensstand krieg ich's leider nicht hin. Mit den Exceptionsabfragen tue ich mir auch noch recht schwer. Hinzu kommt noch, dass der TestPC ein Windows-Firmenrechner ist der nur die JRE installiert hat. Das hat sicher etwas mit meinem Code zu tun (der ist veraltet). 🙄 Ich werde mich jetzt mit dem Schnipsel:
Java:
void saveResourceTo(File dest, String resource) throws IOException {
    try(InputStream in = getClass().getResourceAsStream(resource)) {
        Files.copy(in, dest.toPath());
    }
}
auseinandersetzen. Probiert habe ich's zwar schon, kriege aber in der IDE ständig fehler. Vielleicht macht mir Java ja ein Weihnachtsgeschenk in Form eines funktionierenden Hilfe.pdf das zur Laufzeit aus dem *.jar auf einem Windowsrechner geladen wird... 🙂
 
Mal eine ganz dumme Idee: kann es sein, dass Du das jar auf dem Windowsrechner per Doppelklick aufrufst und deshalb überhaupt keine Fehler siehst? Wenn ja, starte das Ding doch mal über die Befehlszeile (EDIT: natürlich mit java.exe und nicht mit javaw.exe)
 
Ich hab's soeben über die Befehlszeile gestartet und bekomme folgende Fehlermeldung:
Code:
Fehler: Hauptklasse h:\test.jar konnte nicht gefunden oder geladen werden
Ich habe meine test.jar in der NetbeansIDE mit jar erstellen und bereinigen erstellt.
 
Zuletzt bearbeitet:
Code:
H:
cd \
java -jar test.jar

bzw. wenn Du keine Libs brauchst:
Code:
java -jar H:\test.jar
 
Eingabe von
java -jar H:\test.jar
ergibt golgende Ausgabe:
Code:
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. Alle Rechte vorbehalten.

java -jar h:\test.jar
Dez 20, 2018 8:47:57 AM test.Test$1 mouseClicked
SCHWERWIEGEND: null
java.io.IOException: Failed to open C:\Users\user\AppData\Local\Temp\Hilfe552
6452732798370058pdf. Error message: Der angegebenen Datei ist keine Anwendung zu
geordnet.

        at sun.awt.windows.WDesktopPeer.ShellExecute(Unknown Source)
        at sun.awt.windows.WDesktopPeer.open(Unknown Source)
        at java.awt.Desktop.open(Unknown Source)
        at test.Test$1.mouseClicked(Test.java:199)
        at java.awt.AWTEventMulticaster.mouseClicked(Unknown Source)
        at java.awt.Component.processMouseEvent(Unknown Source)
        at javax.swing.JComponent.processMouseEvent(Unknown Source)
        at java.awt.Component.processEvent(Unknown Source)
        at java.awt.Container.processEvent(Unknown Source)
        at java.awt.Component.dispatchEventImpl(Unknown Source)
        at java.awt.Container.dispatchEventImpl(Unknown Source)
        at java.awt.Component.dispatchEvent(Unknown Source)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
        at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
        at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
        at java.awt.Container.dispatchEventImpl(Unknown Source)
        at java.awt.Window.dispatchEventImpl(Unknown Source)
        at java.awt.Component.dispatchEvent(Unknown Source)
        at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
        at java.awt.EventQueue.access$500(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionP
rivilege(Unknown Source)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionP
rivilege(Unknown Source)
        at java.awt.EventQueue$4.run(Unknown Source)
        at java.awt.EventQueue$4.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionP
rivilege(Unknown Source)
        at java.awt.EventQueue.dispatchEvent(Unknown Source)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.run(Unknown Source)
 
Habe mir die Hilfe.pdf aus dem jar-File rausgeholt und mit doppeklick geöffnet - sie wird mit dem Adobe Acrobat Reader DC geöffnet...
 
Ach, jetzt habe ich es gesehen: Du schreibst die Datei ohne "." vor der Erweiterung raus: 234234pdf statt 234234.pdf -> da kommt Windows nicht zurecht.

Nachtrag: es geht um die Zeile
Java:
tempOutputFile = File.createTempFile( "Hilfe", "pdf" );

Ganz am Anfang hattest Du es richtig:
Java:
tempOutputFile = File.createTempFile( "Hilfe", ".pdf" );
 
Mann, wenn's das gewesen ist! Werde ich heute am Abend gleich mal zu Hause ändern und ne neue test.jar erstellen und morgen dann wieder in der Arbeit probieren... 😀
Vielen Dank vorerst mal - wie schon mal gesagt, was würde ich ohne mihe7 machen 🙂
jacl
 
Yes, der Punkt beim "pdf" war's.
Java:
tempOutputFile = File.createTempFile( "Hilfe", ".pdf" );
Ohne Punkt kein Ende 😀 - jetzt funtionierts auch unter Windows.
Vielen Dank für die Hilfe und fröhliche Weihnachten inklusive Feiertage...
Jacl 🙂
 

Neue Themen


Zurück
Oben