[Java]Process output vangen

Pagina: 1
Acties:

  • Deddiekoel
  • Registratie: Maart 2000
  • Laatst online: 12-11-2025

Deddiekoel

Gadget nerd

Topicstarter
Ik ben sinds kort weer een beetje met Java aan het spelen gegaan en zit nu in de fase dat ik vooral kleine (zinloze?) apps aan het maken ben.
Wat ik momenteel aan het proberen ben is om windows programma's te starten vanuit Java. Ik gebruik hiervoor runtime.exec() en hiermee onstaat een Process object.

Mijn probleem is nu dat het Process dat ik wil opstarten niet te volgen is. Ik start namelijk een (DOS) programma op dat gaat zitten luisteren naar specifieke boodschappen. Als ik dit programma opstart vanuit de commandline (of .bat file) dan opent er een command window waarin de aktiviteiten van dat programma staan ("Listening"). Dit effect wil ik ook krijgen in Java, ik wil dat de ouput van dat programma weergeven in een eigen venster. Het liefst ook op een manier dat de hoofdapplicatie (waarmee ik de applicatie start) gewoon door kan gaan en eventueel andere applicaties kan starten!

Hetgeen ik wil bereiken is dat ik een eenvoudige GUI heb om commandline commando's mee te maken en deze te runnen.

Verlanglijstje: Switch 2, PS5 Pro Most wanted: Switch 2


  • nxt
  • Registratie: November 2001
  • Laatst online: 04-02 09:36

nxt

aan de instantie Process die je terug krijgt
kun je met behulp van de methods
getInputStream(), en getOutputStream() een in/outputstream en de output van het process uitlezen

als je wilt dat je 'hoofd' applicatie verder gaat zul je eens moeten kijken naar Thread en Runnable

  • Deddiekoel
  • Registratie: Maart 2000
  • Laatst online: 12-11-2025

Deddiekoel

Gadget nerd

Topicstarter
Het is me inmiddels gelukt om de output van een process af te vangen. Dat doe ik met de volgende code:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    public String executeCommand(String cmd) throws Exception {
    String returnValue = new String();
    int exitValue           = 0;
    try {
        Runtime rt          = Runtime.getRuntime();
        Process executedProcess = rt.exec(cmd);
        InputStream in      = executedProcess.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        String line;
        while((line = br.readLine())!=null){
        if(!line.trim().equals("")) returnValue += line+"\n";   
        }
        executedProcess.waitFor();
    }
    catch (Exception e) {
        e.printStackTrace();
        throw e;
    }
    return returnValue;
    }

Als ik deze code in een Thread draai werkt dit op zich goed voor bepaalde commandos. Het probleem is dat het dus niet werkt voor alle commandos. Zo vang ik bijvoorbeeld wel de code af van een "tracert" of "ipconfig" commando. Maar niet van een "sc" of "net" commando. Ik snap alleen niet hoe dit kan.

Om de commandos in te voeren gebruik ik een String als invoer. Maar ik wilde via deze manier en het sc.exe wat invloed uitoefenen op windows services maar ik krijg dat programma dus niet gedraaid. Waar kan dit aan liggen?

Edit: sc werkt eigenlijk gewoon wel, maar alleen als correct commandos invoer (zoals "sc query Messenger"). De messages met daarin uitleg vangt hij niet af (als je bijv alleen sc invoert). Is er een manier om alle output af te vangen? Zodat ik bijvoorbeeld "sc query Messenger | find "RUNNING" " kan uitvoeren.

[ Voor 14% gewijzigd door Deddiekoel op 20-09-2004 09:47 ]

Verlanglijstje: Switch 2, PS5 Pro Most wanted: Switch 2


  • Macros
  • Registratie: Februari 2000
  • Laatst online: 30-04 09:28

Macros

I'm watching...

Misschien wordt sommige text met errorInputStream wel verzonden?

"Beauty is the ultimate defence against complexity." David Gelernter


Verwijderd

Je zou natuurlijk kunnen proberen om met IO-redirection de output naar een file te sturen en het vanuit daar te lezen. e.g. netstat -a > out.tmp

  • Robtimus
  • Registratie: November 2002
  • Laatst online: 20:53

Robtimus

me Robtimus no like you

Even offtopic, maar ipv een String kun je beter een StringBuffer gebruiken:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public String executeCommand(String cmd) throws Exception {
    StringBuffer returnValue = new StringBuffer();
    int exitValue = 0;
    try {
        Runtime rt = Runtime.getRuntime();
        Process executedProcess = rt.exec(cmd);
        InputStream in = executedProcess.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        String line;
        while((line = br.readLine())!=null) {
            if(!line.trim().equals("")) {
                returnValue.append(line).append('\n');
            }
        }
        executedProcess.waitFor();
    } catch (Exception e) {
        e.printStackTrace();
        throw e;
    }
    return returnValue.toString();
}
Is een stuk efficienter.

More than meets the eye
There is no I in TEAM... but there is ME
system specs


  • Robtimus
  • Registratie: November 2002
  • Laatst online: 20:53

Robtimus

me Robtimus no like you

Verwijderd schreef op 20 september 2004 @ 10:47:
Je zou natuurlijk kunnen proberen om met IO-redirection de output naar een file te sturen en het vanuit daar te lezen. e.g. netstat -a > out.tmp
Dan kun je alsnog de error stream niet lezen.

Lezen mbv de inputstream kan wel, maar dan moet je het commando aanpassen: commando 2>&1 (maw: stderr wordt naar stdout geschreven)

More than meets the eye
There is no I in TEAM... but there is ME
system specs


  • Deddiekoel
  • Registratie: Maart 2000
  • Laatst online: 12-11-2025

Deddiekoel

Gadget nerd

Topicstarter
IceManX schreef op 20 september 2004 @ 11:06:
Even offtopic, maar ipv een String kun je beter een StringBuffer gebruiken:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public String executeCommand(String cmd) throws Exception {
    StringBuffer returnValue = new StringBuffer();
    int exitValue = 0;
    try {
        Runtime rt = Runtime.getRuntime();
        Process executedProcess = rt.exec(cmd);
        InputStream in = executedProcess.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        String line;
        while((line = br.readLine())!=null) {
            if(!line.trim().equals("")) {
                returnValue.append(line).append('\n');
            }
        }
        executedProcess.waitFor();
    } catch (Exception e) {
        e.printStackTrace();
        throw e;
    }
    return returnValue.toString();
}
Is een stuk efficienter.
Goed om te weten. Maar ik wil dan toch ook weten waarom dat efficienter is...

Verlanglijstje: Switch 2, PS5 Pro Most wanted: Switch 2


  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Deddiekoel schreef op 20 september 2004 @ 11:09:
Goed om te weten. Maar ik wil dan toch ook weten waarom dat efficienter is...
Omdat een StringBuffer een verzameling characters is (of een verzameling van verzamelingen characters oid) en je met append iets aan die verzameling toevoegt. Bij String-concattenatie maak je bij elke concattenatie een nieuw String-object aan.

En hoe langer de String, hoe erger het verschil wordt omdat de originele String steeds opnieuw gekopieerd moet worden en aangevuld moet worden met het aangeplakte deel. Sterker nog, intern wordt het al met een StringBuffer uitgevoerd omdat een String "immutable" is (de inhoud wijzigt nooit nadat ie eenmaal aangemaakt is, voor een wijziging moet je een nieuw object maken), maar dan veel inefficienter dan wanneer je direct een StringBuffer zou toepassen.

Om het met code te illustreren:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
String s = "blaat";
s += "blaat";
s += "blaat";
s += "blaat";

// Wordt intern uitgevoerd als:
String s = "blaat";
StringBuffer temp = new StringBuffer(s);
temp.append("blaat");
s = temp.toString();
StringBuffer temp = new StringBuffer(s);
temp.append("blaat");
s = temp.toString();
StringBuffer temp = new StringBuffer(s);
temp.append("blaat");
s = temp.toString();

// Terwijl dit natuurlijk veel efficienter is:
StringBuffer temp = new StringBuffer("blaat");
temp.append("blaat");
temp.append("blaat");
temp.append("blaat");
s = temp.toString();

[ Voor 44% gewijzigd door ACM op 20-09-2004 11:36 ]


  • Robtimus
  • Registratie: November 2002
  • Laatst online: 20:53

Robtimus

me Robtimus no like you

Ik heb eens een test uitgevoerd met 10000 iteraties waarin aan een lege string/stringbuffer steeds de string "bla " werd geplakt.

De string versie had 811 keer een geheugenopruiming nodig, de stringbuffer versie slechts 4. En dan nog had de stringbuffer versie op het einde minder geheugen in gebruik.

De stringbuffer had zo goed als geen tijd nodig voor dit (time taken was steeds 0), de string versie rond de 1160 ms.

Dus StringBuffer.append heeft minder geheugen nodig en is een stuk sneller.

More than meets the eye
There is no I in TEAM... but there is ME
system specs


  • Deddiekoel
  • Registratie: Maart 2000
  • Laatst online: 12-11-2025

Deddiekoel

Gadget nerd

Topicstarter
Goed om te weten!
Ondertussen heb ik de code wat uitgebreid met het afvangen van de errorstream:
:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public String executeCommand(String cmd) throws Exception {
    StringBuffer returnValue = new StringBuffer();
    int exitValue = 0;
    try {
        Runtime rt = Runtime.getRuntime();
        Process executedProcess = rt.exec(cmd);
        InputStream in = executedProcess.getInputStream();
        InputStream err = executedProcess.getErrorStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        String line;
        while((line = br.readLine())!=null) {
            if(!line.trim().equals("")) {
                returnValue.append(line).append('\n');
            }
        }
        br = new BufferedReader(new InputStreamReader(err));
        while((line = br.readLine())!=null) {
            if(!line.trim().equals("")) {
                returnValue.append(line).append('\n');
            }
        }
        executedProcess.waitFor();
    } catch (Exception e) {
        e.printStackTrace();
        throw e;
    }
    return returnValue.toString();
}

Dit lijkt goed te werken, maar is dit wel een goede oplossing?

[ Voor 12% gewijzigd door Deddiekoel op 20-09-2004 22:11 ]

Verlanglijstje: Switch 2, PS5 Pro Most wanted: Switch 2


  • Jrz
  • Registratie: Mei 2000
  • Laatst online: 19:11

Jrz

––––––––––––

Ennnnnnnnnn laat losssssssss.... https://github.com/jrz/container-shell (instant container met chroot op current directory)


  • Robtimus
  • Registratie: November 2002
  • Laatst online: 20:53

Robtimus

me Robtimus no like you

Deddiekoel schreef op 20 september 2004 @ 14:11:
Goed om te weten!
Ondertussen heb ik de code wat uitgebreid met het afvangen van de errorstream:
:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public String executeCommand(String cmd) throws Exception {
    StringBuffer returnValue = new StringBuffer();
    int exitValue = 0;
    try {
        Runtime rt = Runtime.getRuntime();
        Process executedProcess = rt.exec(cmd);
        InputStream in = executedProcess.getInputStream();
        in = executedProcess.getErrorStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        String line;
        while((line = br.readLine())!=null) {
            if(!line.trim().equals("")) {
                returnValue.append(line).append('\n');
            }
        }
        br = new BufferedReader(new InputStreamReader(err));
        while((line = br.readLine())!=null) {
            if(!line.trim().equals("")) {
                returnValue.append(line).append('\n');
            }
        }
        executedProcess.waitFor();
    } catch (Exception e) {
        e.printStackTrace();
        throw e;
    }
    return returnValue.toString();
}

Dit lijkt goed te werken, maar is dit wel een goede oplossing?
Je vangt dus eerst de output stream af, en daarna pas de error stream? Dat lijkt me iig de bedoeling, want dit zal niet compilen, err is niet gedeclareerd ;)

Maar wat als error stream data en output stream data door elkaar komen? De volgorde is zo niet meer correct. Door de ene stream naar de ander te redirecten vang je dat probleem af.

More than meets the eye
There is no I in TEAM... but there is ME
system specs


  • Deddiekoel
  • Registratie: Maart 2000
  • Laatst online: 12-11-2025

Deddiekoel

Gadget nerd

Topicstarter
Klopt, die code is even hier snel aangepast en niet een copy paste.
Met err declared werkt hij wel. Ik heb mijn bericht al aangepast.

Verlanglijstje: Switch 2, PS5 Pro Most wanted: Switch 2

Pagina: 1