Problem beim lesen des InputStreams von einem Subprozess

halim

Mitglied
Servus java-forum,

bin neu hier und hoffe, dass ich hier richtig gepostet habe. Wenn nicht, bitte in richtigen Bereich verschieben.

Zu meinem Problem:
Ich habe ein Java Programm geschrieben, dass ein Subprozess startet und in einem Thread die Ausgabe davon lesen soll. Mit Hilfe von Google habe ich alles nötige zu diesem Thema gefunden, leider funktioniert das mit manchen Prozessen nicht richtig.

Ich verwende Ubuntu und arbeite mit NetBeans. Mit manchen Programmen klappt es, mit anderen wiederum nicht. "glxgears" ist ein Programm mit dem es nicht richtig funktioniert, hier der Source Code:
Die Main Klasse mit der main(..) Methode:
Java:
package outputreader;

public class Main{
    public static void main(String[] args){
        Process p = null;
        try{
            String[] cmd = {"/bin/sh", "-c", "glxgears"};
            p = Runtime.getRuntime().exec(cmd);//hier habe ich auch versucht direkt "glxgears" zu schreiben, liefert aber das gleiche Ergebnis
        }catch(Exception ex){
            System.out.println("Can't create process");
        }
        Thread stdout = new OutputReader(p.getInputStream());
        stdout.start();
        
        Thread stderr = new OutputReader(p.getErrorStream());
        stderr.start();
    }
}
Der Thread, der die Ausgabe lesen soll:
Java:
package outputreader;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

class OutputReader extends Thread{
    private BufferedReader br;
    private InputStream is;
    
    OutputReader(InputStream is){
        this.is = is;
        this.br = new BufferedReader(new InputStreamReader(is));
    }
    
    @Override
    public void run(){
        while(true){
            String s;
            int i;
            try {
                while((i = is.read()) != -1){
                    System.out.print((char) i);
                }
            } catch (IOException ex) {
                System.out.println("InputStream.read() exception, e: "+ex.getMessage());
            }
            
                        
            //---------------
            /*
            try{
                while((s = br.readLine()) != null){
                    System.out.println("Zeile: "+s);
                }
            }catch(IOException ex){
                System.out.println("BufferedReader.readLine() exception, e: "+ex.getMessage());
            }*/

        }
    }
    
}

Wie ihr in der run() Methode des Threads sieht, habe ich auf 2 verschiedene Arten versucht den InputStream auszulesen.
1. direkt über den InputStream mit der read() Methode, Zeichen für Zeichen auslesen.
2. mit einem BufferedReader eine Zeile als String auslesen.

Beide Vorgehensweisen liefern exakt die gleichen Ergebnisse:
glxgears, das Programm, wird gestartet. Aber ich bekomme keine Ausgabe.
Erst wenn ich das Programm per klick auf "X" schließe, wird mir alles in die Konsole geschrieben. Während glxgears läuft, passiert nichts.

glxgears terminiert die ausgegebenen Zeilen mit "\n". Hier der Beweis:
Code:
printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds, fps);

Oder hier nachzulesen: http://cvsweb.xfree86.org/cvsweb/xc/programs/glxgears/glxgears.c?rev=1.3

Ich habe für Testzwecke auch ein eigenes Java Programm gechrieben, dass ein mal in der Sekunde was in die Konsole ausgibt und den mit Hilfe des obigen Programms gestartet. Da hat es Wunderbar geklappt, alle Ausgaben konnten gelesen werden.

Hier der Source Code zum Testprogramm:
Java:
public class main{
    public static void main(String args[]){
        Thread t = new DoSomeOutput();
        t.start();
    }
}
//Thread:
class DoSomeOutput extends Thread{

    @Override
    public void run(){
        int i = 0;
        while(true){
            try{
                System.out.println("Zähler: "+(i++));
                Thread.sleep(1000);
            }catch(InterruptedException ex){
                System.out.println("Kann nicht schlafen :(");
            }
        }
    }  
}

Ich hoffe, dass ich alles notwendige erwähnt habe und ihr mir helfen könnt.


MfG

Halim
 
Hallo halim,

das Phänomen erklären kann ich. Ich habe aber leider keine Lösung.

Der "Bösewicht" versteckt sich im Quellcode des glxgears und Zwar in dieser Zeile:
#include <stdio.h>

Die stdio Bibliothek arbeitet mit Puffern. Wenn stdout/stderr mit einer Shell verbunden sind, merkt die stdio das und flusht den Puffer bei jedem Auftreten eines Linefeed.

Aber, wenn stdout/stderr mit einer Pipe verbunden sind (und das sind sie bei Aufruf durch Java) dann wird der Puffer nicht bei Auftreten eines Linefeed geflusht, sondern erst, wenn er voll ist oder, wenn der Prozess beendet wird.
 
Danke für die schnelle Antwort! Ich verstehe das mit dem flushen der Puffer nicht ganz. Meine C/C++ Kentnisse sind nicht allzu gut.

Von Java aus kann man da nichts machen oder kann man dieses Problem irgendwie seitens der C/C++ Anwendung (z.B. glxgears) umgehen?
 
halim hat gesagt.:
Meine C/C++ Kentnisse sind nicht allzu gut.
Und meine sind praktisch gleich Null 😳

halim hat gesagt.:
Von Java aus kann man da nichts machen oder kann man dieses Problem irgendwie seitens der C/C++ Anwendung (z.B. glxgears) umgehen?
Von Java aus kann man da nichts machen. Du hast von Seiten des Empfängers keinen Einfluss darauf, wie der Sender seine Daten versendet. Und den zweiten Teil Deiner Frage kann ich Dir leider nicht wirklich beantworten. In einem Link zu dem Thema (allerdings ganz anderer Zusammenhang): pexpect - Noah.org
schlägt der Autor vor, entweder das entsprechende Programm neu zu kompilieren, um das Pufferungsverhalten zu beeinflussen, oder es über Pseudo-Terminals anzusprechen. Bei beidem muss ich leider passen.
 
Zuletzt bearbeitet von einem Moderator:
Danke vielmals für deine Hilfe. Ich werde vermutlich die Ausgabe des Programms direkt umlenken (prog >> output.txt) und in eine Textdatei schreiben lassen. Von dort wird dann mein Java Programm auslesen.

Dieses Problem über Pseudo Terminals zu lösen würde bedeuten, dass das Programm zu sehr an Platformunabhängigkeit verliert (ich kenne keine alternative unter Windows). Andere Lösungswege fallen mir auch nicht ein.
 

Neue Themen


Zurück
Oben