"We are back" « oc.at

[java] Best practice für Interaktion mit externen Programmaufrufen?

semteX 21.06.2009 - 20:22 3460 25
Posts

semteX

begehrt die rostschaufel
Avatar
Registered: Oct 2002
Location: Pre
Posts: 14809
Wie es grundsätzlich funktioniert ist klar:

http://www.rgagnon.com/javadetails/java-0014.html

die frage die ich mir da stell: solang ich weiß, welche eingabe / ausgabe da daher kommt, geht das relativ gemütlich.

aber was ist, wenn ich zu jedem zeitpunkt im externen programm mit benutzerinteraktion rechnen muss? und vor allem: Wie vermeid ich, dass ich mein programm "überhole"? also ich start das ding und les danach den InputStream aus => Ich bekomm also mal alle konsolen ausgaben, welche bis zum zeitpunkt X abgearbeitet wurde... jetzt ist aber grad die operation besonders rechenintensiv => InputStream sagt "ich hab nix mehr", bricht ab... obwohl der prozess noch fröhlich rechnet und zu einem späteren zeitpunkt ausgabe erzeut...

ich müsst eigentlich dauernd loopen (bis der prozess beendet ist) und fragen "hast noch was? hast noch was?".

das ist irgendwie massiv ungeschickt. Gibts da ne ordentliche best practice dazu?

DirtyHarry

aka robobimbo
Avatar
Registered: Apr 2001
Location: outer space
Posts: 464
edit: bullshit gelöscht

neuer bullshit:


ganze einfach mit

Code:
public int read(char[] cbuf,
                int off,
                int len)
         throws IOException

und bei len angeben Integer.MAX_VALUE sollte er solange blocken bis das eigentliche read nur mehr EOF oder ERROR zurückgibt.

es gibt dann jedenfalls die gelesenen bytes zurück und im chararray hast du deine daten (sieh auch javadoc)
Bearbeitet von DirtyHarry am 21.06.2009, 23:14

Mr. Zet

Vereinsmitglied
resident spacenerd
Avatar
Registered: Oct 2000
Location: Edge of Tomorrow
Posts: 12066
Der Link ist voll mit mehr oder weniger zusammenhängenden Beispielen. Was genau hast du vor?

Du willst den Output eines anderen Programms lesen und auswerten?

Wenn du nur readLine() verwendest, musst du ja sowieso in einer Loop laufen, sonst hörst du ja schon nach der ersten Zeile auf, auch wenn 20 daher kommen.

Ich würde einfach lesen - verarbeiten - lesen - verarbeiten etc. bis halt irgend eine Bedingung erfüllt ist, die dir sicher sagt, es kommt nichts mehr (falls es so etwas gibt).

Ohne genauere Informationen darüber, was du damit bezweckst, würde ich jetzt aber eher mal ins Blaue raten und sagen der ganze Ansatz ist nicht unbedingt besonders geeignet.

semteX

begehrt die rostschaufel
Avatar
Registered: Oct 2002
Location: Pre
Posts: 14809
naja, es geht darum externe programme möglichst flexibel "aufzurufen"...

Ich hab selbst noch etwas gegrübelt (mit support) und das beste scheint echt ne thread lösung zu sein:

Hauptthread startet den Prozess. Danach startet der Mainthread den Reader Thread, welcher den InputStream, und den Writer, welcher den Output stream verarbeitet. Danach macht der nix anderes mehr als auf das ende des Prozesses zu warten (waitFor()) und die Threads zu killen.

der Reader - Thread muss sich loopen (am besten mit thread.sleep(500) in der loop) und den ganzen content des buffers raushaun. Der Writer thread kann eh im status des "warte auf keyboard input" blockieren...

ih finds schiach

Mr. Zet

Vereinsmitglied
resident spacenerd
Avatar
Registered: Oct 2000
Location: Edge of Tomorrow
Posts: 12066
Inputstream = Input in dein Programm = Output des externen Programms?
Outputstream = Output DEINES Programms?

Muss das ganze "realtime" sein?

Die ganz entscheidenden Fragen sind sowieso:
a) in welcher Form ist der Output des externen Programms (kontinuierlicher Stream, Zeilenweise, etc)
b) hast du darauf Einfluss?

semteX

begehrt die rostschaufel
Avatar
Registered: Oct 2002
Location: Pre
Posts: 14809
der inputstream eines prozesses in java ist der mist, der auf der konsole rauskommt :D

und form des outputs ist ned spezifiziert, sonst wärs ja feig

edit: ich werds morgn eh mal ausimplementiern

DirtyHarry

aka robobimbo
Avatar
Registered: Apr 2001
Location: outer space
Posts: 464
habs jetzt mal ausgetestet - sollte funktionieren, nachteil ist - du musst vorher schon die buffersize kennen, und testen ob da nicht irgendwann ein anderes timeout reinhaut :)

Code:
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        byte[] b = new byte[65535];
        try {
            String line;
            Process p = Runtime.getRuntime().exec(System.getenv("windir") + "\\system32\\" + "tree.com /A");
            DataInputStream input =
                    new DataInputStream(p.getInputStream());
            input.readFully(b);
            input.close();

        } catch (EOFException ex) {
            String line = new String(b);
            System.out.println(line);
        } catch (Exception err) {
            err.printStackTrace();
        }

    }
}

edit: das mit der eof-ex ist ein wenig dirty, es kann ja auch sein dass sie nicht auftritt - dann steck am besten die ausgabe ins finally
Bearbeitet von DirtyHarry am 22.06.2009, 00:00

Mr. Zet

Vereinsmitglied
resident spacenerd
Avatar
Registered: Oct 2000
Location: Edge of Tomorrow
Posts: 12066
Gut nach mehrmaligem Lesen deiner Posts verstehe ich dein Problem nun nicht mehr.

Allgemeiner Tipp zum Abschluss: Nicht spezifizierte Punkte eines Auftrages wirft man dem Auftraggeber am besten vor die Füße zum Nachbessern, denn in 99% der Fälle wird dir das später auf den Kopf fallen...

semteX

begehrt die rostschaufel
Avatar
Registered: Oct 2002
Location: Pre
Posts: 14809
Zitat von Mr. Zet
Gut nach mehrmaligem Lesen deiner Posts verstehe ich dein Problem nun nicht mehr.

Allgemeiner Tipp zum Abschluss: Nicht spezifizierte Punkte eines Auftrages wirft man dem Auftraggeber am besten vor die Füße zum Nachbessern, denn in 99% der Fälle wird dir das später auf den Kopf fallen...
es ist kein auftrag, es ist etwas, was mich einfach persönlich interessiert und wo ich keine zufriedenstellende lösung gefunden hab... ich werd das morgn etwas ausführlicher ausführen

watchout

Legend
undead
Avatar
Registered: Nov 2000
Location: Off the grid.
Posts: 6845
Schonmal die Doku zu Streams in Java (http://java.sun.com/javase/6/docs/a...nputStream.html) durchgelesen?

Wenn du ein externes Programm aufrufst (und überhaupt wenn du dessen Output verarbeiten willst) sollte aber in jedem Fall ein eigener Thread her, damit du dein Hauptprogramm nicht blockst...

@Zet: Schon was von blocking read gehört? :p Sysprog, DSLab, ... *HUST*

Achja kurz gesagt: Einen Stream kann man so lesen dass der lesende Thread blockiert wenn dieser leer ist, genauergesagt ist das die "default" Verwendung, also nicht
Code:
Hast noch was?
Ne
Hast noch was?
Ne
Hast noch was?
Ne
Hast noch was?
Ne
Sondern
Code:
A: Hast noch was?
B: Wart mal.
.... (45s später)
B: Da hast
A: Hast noch was?
B: Wart mal.
.... (10 Tage, 3h, 37m, 45s später)
B: Da hast
Das ganze geht am besten dann über einen BufferedReader dann kann man das auch schön in kleinen (Zeilenweisen) stückchen auswerten

alles klar? :)

Mr. Zet

Vereinsmitglied
resident spacenerd
Avatar
Registered: Oct 2000
Location: Edge of Tomorrow
Posts: 12066
watchout... a geh wirklich!

Genau weil ich das weiß, versteh ich ja dem semtex sein Problem nicht :p

watchout

Legend
undead
Avatar
Registered: Nov 2000
Location: Off the grid.
Posts: 6845
Zet: Vielleicht weiß er es nicht? ;)

semteX

begehrt die rostschaufel
Avatar
Registered: Oct 2002
Location: Pre
Posts: 14809
das ist richtig, dass das ding blocking read macht war mir nicht bewusst... gut das erleichtert einiges.

außerdem könnt ich mal wieder paar stunden freizeit brauchn :D

Ringding

Pilot
Avatar
Registered: Jan 2002
Location: Perchtoldsdorf/W..
Posts: 4300
Es ist aber gar nicht so einfach, wie es zunächst scheint. Wenn ein Prozess abwechselnd etwas von stdin liest und dann als Antwort darauf etwas auf stdout schreibt, dann wieder liest usw. [1], dann kann man nicht die komplette Eingabe in einem Rutsch am Anfang reinschreiben, weil dann irgendwann die Pipe-Buffer vollwerden und die ganze Geschichte hängenbleiben wird. In POSIX braucht man dafür dann select; welche Mechanismen Java anbietet, weiß ich nicht (würde mich aber interessieren ;)).

[1] wie es z.B. ein HTTP-Server tut; allerdings nicht auf stdin/stdout.

DirtyHarry

aka robobimbo
Avatar
Registered: Apr 2001
Location: outer space
Posts: 464
soweit ich weiss liest in java der Stream aus der pipe in seinen eigenen puffer
Kontakt | Unser Forum | Über overclockers.at | Impressum | Datenschutz