Runtime.getRuntime().exec nebenbei ausführen

truesoul

Top Contributor
Hallo miteinander,

ich habe ein kleines Problem und ich hoffe ihr wisst dies zu Lösen 🙂
Es geht darum das ich eine Datei konvertiere während natürlich die GUI noch ansprechbar ist.
Dies tue ich mit
Java:
 Runtime.getRuntime().exec("ffmpeg -i C:\\Trailer.mp4 -vn C:\\audio3.mp3");
und ich Arbeite natürlich mit Threads. Ich habe euch mal ein Beispiel gebastelt ...

Java:
public class BeispielProgramm extends javax.swing.JFrame {


    public BeispielProgramm() {
        initComponents();
    }


    @SuppressWarnings("unchecked")
    
    private void initComponents() {

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        panel = new javax.swing.JPanel();
        panel.setLayout(new java.awt.BorderLayout());

        nebenbei = new javax.swing.JLabel();
       
        starteAktion = new javax.swing.JButton();
        starteAktion.setText("Start");
        starteAktion.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                starteAktionActionPerformed(evt);
            }
        });

        panel.add(starteAktion, java.awt.BorderLayout.PAGE_START);
        nebenbei.setText("");
        panel.add(nebenbei, java.awt.BorderLayout.CENTER);
        getContentPane().add(panel, java.awt.BorderLayout.CENTER);

        pack();
    }

    private void starteAktionActionPerformed(java.awt.event.ActionEvent evt) {
        new NebenbeiThread().start();
        new RuntimeThread().start();
    }

    class NebenbeiThread extends Thread{

        @Override
        public void run() {
            int i = 0;
            while(true){
                try{
                    nebenbei.setText(""+i);
                    this.sleep(1000);
                    i++;
                }catch( Exception e){
                    System.out.println(e.getMessage());
                }
             }
        }
    }

    class RuntimeThread extends Thread{

        @Override
        public void run() {
            try{
                 // Muss ja nicht unbedingt diese Aktion sein, gilt auch für andere Aktionen
                 Runtime.getRuntime().exec("ffmpeg -i C:\\Trailer.mp4 -vn C:\\audio3.mp3");

           }catch (Exception e){
                System.out.println(e.getMessage());
           }
        }

    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new gg().setVisible(true);
            }
        });
    }

    private javax.swing.JPanel panel;
    public javax.swing.JLabel nebenbei;
    private javax.swing.JButton starteAktion;

}

So und nun das Problem:

Das konvertieren von mp4 zu mp3 geschieht erst nachdem ich die GUI schliesse?!? Was kann ich tun, damit dies, während ich die GUI offen, habe geschieht?

Gruß
 
Hallo Hoax,

also ich hoffe ich habe dich richtig verstanden. Also sollte ich sowas wie :

Java:
Runtime r = Runtime.getRuntime();
Process p = r.exec("cmd.exe /c start ffmpeg -i C:\\Trailer.mp4 -vn C:\\audio3.mp3");
BufferedReader is = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = is.readLine()) != null){
          System.out.println(line);
          System.out.flush();
}
machen ? ( Hier bekomme ich allerdings keine Ausgabe )
Oder meintest du was anderes? 🙂

Gruß
 
Bekomme leider garnichts zurück ?!

Java:
try{
Runtime r = Runtime.getRuntime();
Process p = r.exec("cmd.exe /c start ffmpeg -i C:\\Trailer.mp4 -vn C:\\audio3.mp3");
BufferedReader is = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String line;
String line2;
while ((line = br.readLine()) != null)
{
         System.out.println(line);
}

while ((line2 = in.readLine()) != null)
{
         System.out.println(line);
}


}catch( Exception e){

}
Also die audio Datei wird erstellt aber erst nach Programmende wird die konvertierung durchgeführt ??!
Im Prinzip will ich keine Ausgabe erhalten sondern das die konvertierung ausgeführt wird, ich habe nämlich das gefühl das ich mich falsch ausgedrückt habe 🙂

Edit:

Die Konvertierung funktioniert, endlich !!! ... mein Tag ist gerettet 😀 (mein Fehler)
 
Zuletzt bearbeitet:
also davon abgesehen das der oben gepostete code *nach der änderung von gg.start* auf anhieb funktioniert *bei mir kommt natürlich der error : ffmpeg not found ... ist deine klasse schon sehr suspekt ...
1) hast du schon mal was von IMPORT gehört oder nutzt du eine IDE die das einfach nich kann ? ... weil es ist eher unüblich in einer ganzen klasse immer die absoluten class-namen anzugeben ... das importieren der klassen *oder falls resourcen nicht so eng bemessen sein müüsen* des ganzen package ist die praxis-methode ... das angeben des absoluten namens beschränkt sich lediglich auf sonderfälle wenn man in den importierten packages mehrere klassen hat die den selben namen haben ... in der regel meckert da aber schon der compiler
2) warum erstellst du erst ein JPanel ... setzt diesem noch nicht mal ein layout ... fügst diesem dann objekte zu mit angaben des borderlayouts ... addest das dann in das jcontentpane und rufst dann auch noch sinngerweise pack auf ...
um das mal aus einander zu nehmen
2a) du bruachst kein gesondertes panel oder pane solange du keine speziellen dinge davor legen willst wie ein jscrollpane oder ein tabbedpane oder sowas ... du kannst die elemente dierekt dem frame oder window hinzufügen
2b) wenn man sich schon überlegt beim adden layout-parameter mit anzugeben sollte man das auch vorher dem entsprechenden objekt zuweisen und sich nicht auf compiler-optimierung verlassen
2c) da pack schon noch vor dem anzeigen aufgerufen wird holt es sich erstmal die pefferedsize der enthaltenen objekte ... da ein jlabel mit dem string "" jedoch 0x0 zurückliefert un dein button auch nur knapp größer ist als der text der drin steht ist das frame auf mindestgröße zusammengeschrumpft ... folglich sieht man das jlabel erstmal garnicht ohne nicht manuell das fenster größer zu machen ... hier besteht nachbesserungs bedarf ...
3) deine main ist nicht grade schön ... denn der AWTEventQueue-thread läuft nur wenn er gebraucht wird ... und das ist nunmal nicht immer der fall ... besser wäre hier gewesen wenn du das objekt so erstellt hättest und dann nur das setvisible in ein invokelater gepackt hättest ...
4) das konstrukt mit dem anonymen actionlistener ist häufig anzutreffen ... führt aber bei mehreren elementen leicht zu extrem viel overhead-klassen ... und erlich gesagt hätte ich nicht gedacht das der actionlistener die auszuführende methode überhaupt verwenden kann da diese als private deklariert ist und daher eigentlich auch nicht für child-objekte verfügbar ist *oder lieg ich hier doch falsch weil der compiler hat ja nicht gemeckert ^^*

weiteres möcht ich jetzt hier nicht zu sagen da man durch solche dinge nicht auf den stand des entwicklers schließen kann ...
 
Wie ich in meinem ersten Post schon geschrieben habe diente der code nur als Beispiel und die GUI war nicht das Problem, und ja ich kenne imports und ja die benutze ich auch aber dies war nur ein Beispielcode , siehe es als Pseudocode.
Um Zeit zu Sparen habe ich die GUI in paar Sekunden zusammengeklickt gehabt ( Netbeans Editor ).
Mir ist aber auch bewusst das ich Componenten der JFrame direkt hinzufügen kann.

Das mit AWTEventQueue-thread war mir nicht bewusst, danke.

"Das konstrukt mit dem anonymen actionlistener ist häufig anzutreffen ... führt aber bei mehreren elementen leicht zu extrem viel overhead-klassen"

Leuchtet ein und wurde auch nur für diesen Beispiel genutzt. 🙂

Und ja, der Fehler lag daran das ich "gg.start" aufgerufen hatte und nicht Beispielprogramm.start 🙂
 
Gehts denn jetzt zufriedenstellend? Ich frage nur, weil in Deinem 2. Post die Leseoperationen auf den Streams hintereinander im selben Thread laufen und die erste die zweite ggfs. blockiert...
 
gut ... ich endschuldige mich erstmal wegen der sache mit den imports ... dachte halt das du sowas immer machst ... aber wenns nur als pseudo-code dienen soll is das natürlich in ordnung da man so den source einfach copy&paste inne datei packen , compilen und starten kann ...
Ja das Ergebnis stimmt.
naja so lange das wenigstens der fall ist ist ja eigentlich egal WIE
trotzdem würde mich deine lösung interessieren ... weil wie gesagt ... bei mir lief der code sofort ... hast du in deinem richtigen source mit den threads vllt i-was anders gemacht oder hat der Runtime.exec - aufruf irgendwie blockiert ?
ich kenne dieses problem so leider nicht und würde gern die lösung für erfahren falls ich auch mal in sowas komisches rein renne ...

trotzdem gratz das es funzt 😉
 
Ja der fehler lag tatsächlich darin das diese Aktion blockiert wurde. Einfach ein falscher Aufruf wie hier in diesem Code, das kommt davon wenn man zu ungeduldig ist. Meine Anwendung muss mehrere Aktionen gleichzeitig durchführen können (dazu gehört unter anderem das konvertieren) und deshalb Arbeite ich mit Threads. Und der Aufruf war leider nicht im anderen Thread bzw. neuen.

Gruß
 
Zuletzt bearbeitet:
ahh ... ja sowas passiert immer wieder ...
auch mir ... und ich wundere mich dann immer warum meine GUI freezt obwohl im hintergrund die console fleißig arbeitet ...
und dann sucht man im code zeile für zeile ab und debuggt und bastelt alles um und und und ...
aber mal erlich ... ich glaub in sowas rennen selbst noch die profis immer wieder rein xD
aber trotzdem freu ich mich für dich das du es dann doch zum laufen bekommen hast

und zur kleinen anspielung an den AWT-thread

du hast ja gesagt das das file erst nach "programm-ende" erstellt wurde
was ja auch nach logik völlig richtig ist ... weil du im AWT-thread auf objekte in einem anderen thread zugreifen wolltest *ich denk mal das es so passiert ist .. oder zumindest so ähnlich* ... und der andere thread hat aber blockiert und damit der AWT-thread auch ... und nur durch das EXIT konntest du das blockieren lösen ...
wie gesagt : sowas passiert mir auch immer wieder ... nächste mal einfach gleich so versuchen ran zu gehen ... man gewöhnt sich irgendwann dran 🙂
 
also davon abgesehen das der oben gepostete code *nach der änderung von gg.start* auf anhieb funktioniert *bei mir kommt natürlich der error : ffmpeg not found ... ist deine klasse schon sehr suspekt ...
1) hast du schon mal was von IMPORT gehört oder nutzt du eine IDE die das einfach nich kann ? ... weil es ist eher unüblich in einer ganzen klasse immer die absoluten class-namen anzugeben ... das importieren der klassen *oder falls resourcen nicht so eng bemessen sein müüsen* des ganzen package ist die praxis-methode ... das angeben des absoluten namens beschränkt sich lediglich auf sonderfälle wenn man in den importierten packages mehrere klassen hat die den selben namen haben ... in der regel meckert da aber schon der compiler
Es macht null unterschied ob import.* oder nicht. Das optimiert bereits der Compiler.

2) warum erstellst du erst ein JPanel ... setzt diesem noch nicht mal ein layout ... fügst diesem dann objekte zu mit angaben des borderlayouts ... addest das dann in das jcontentpane und rufst dann auch noch sinngerweise pack auf ...
um das mal aus einander zu nehmen
Er setz ein Layout: Zeile 16!?

2a) du bruachst kein gesondertes panel oder pane solange du keine speziellen dinge davor legen willst wie ein jscrollpane oder ein tabbedpane oder sowas ... du kannst die elemente dierekt dem frame oder window hinzufügen
Macht es aber einfacher wenn die GUI noch wächst. Es geht hier um ein Beispiel. Weißt du wieviel Code er rausgelöscht hat bevor er es uns gezeigt hat, nur um es uns einfacher zu machen?

2b) wenn man sich schon überlegt beim adden layout-parameter mit anzugeben sollte man das auch vorher dem entsprechenden objekt zuweisen und sich nicht auf compiler-optimierung verlassen
Wo sind da Compileroptimierungen? Es ist festgeschrieben welches Layout ein JPanel oder JFrame per Default hat. Dass er ein Layout explizit in Zeile 16 setzt hatte ich ja schon erwähnt.

2c) da pack schon noch vor dem anzeigen aufgerufen wird holt es sich erstmal die pefferedsize der enthaltenen objekte ... da ein jlabel mit dem string "" jedoch 0x0 zurückliefert un dein button auch nur knapp größer ist als der text der drin steht ist das frame auf mindestgröße zusammengeschrumpft ... folglich sieht man das jlabel erstmal garnicht ohne nicht manuell das fenster größer zu machen ... hier besteht nachbesserungs bedarf ...
Hat doch erstmal nichts mit dem Fehler zu tun, und es war nirgends die Rede davon, dass es ein fertiges Programm ist. Das sind offensichtliche Dinge die man schon noch behebt, ist ja kein versteckter Bug sondern offensichtlich.

3) deine main ist nicht grade schön ... denn der AWTEventQueue-thread läuft nur wenn er gebraucht wird ... und das ist nunmal nicht immer der fall ... besser wäre hier gewesen wenn du das objekt so erstellt hättest und dann nur das setvisible in ein invokelater gepackt hättest ...
Und durch dass invokeLater wird er gebraucht. Also macht es so wie es da steht keinen nennenswerten Unterschied. Ausgeführt wird es in jedem Fall. Außerdem wird im Konstruktor mit SwingKomponenten gearbeitet, also ist es sogar ehr besser diesen im EventThread ausführen zu lassen!

4) das konstrukt mit dem anonymen actionlistener ist häufig anzutreffen ... führt aber bei mehreren elementen leicht zu extrem viel overhead-klassen ... und erlich gesagt hätte ich nicht gedacht das der actionlistener die auszuführende methode überhaupt verwenden kann da diese als private deklariert ist und daher eigentlich auch nicht für child-objekte verfügbar ist *oder lieg ich hier doch falsch weil der compiler hat ja nicht gemeckert ^^*
Wie willst du ActionListener sonst implementieren? Einen Einzigen der alles bedient? Ich finde es völlig legitim so wies ist, sofern die Aktionen nicht auch noch in anderen Elementen gebraucht werden.
Der Aktionlistener ist eine innere Klasse, und als solche kann sie auf alle Methoden des Besitzern zugreifen.

weiteres möcht ich jetzt hier nicht zu sagen da man durch solche dinge nicht auf den stand des entwicklers schließen kann ...
Dein Wort in Gottes Ohr!

Amen.
 
Zuletzt bearbeitet:

Zurück
Oben