I want to run PianoBar from a Java GUI (PianoBar is a program that runs Pandora from command line). I thought this would be quick and dirty, but I guess I don't know enough about interaction between programs.
I use ProcessBuilder to launch an instance of PianoBar like so:
private Process createPianoBarProcess() throws IOException {
String[] command = {"CMD", "/C", "pianobar"};
ProcessBuilder probuilder = new ProcessBuilder( command );
probuilder.redirectErrorStream(true);
probuilder.directory(new File("~~location where pianobar.exe is~~"));
Process process = probuilder.start();
return process;
}
After I create the process, I create a BufferedReader to read in the PianoBar output:
Process pianoBar = createPianoBarProcess();
InputStream inS = pianoBar.getInputStream();
InputStreamReader isr = new InputStreamReader(inS);
BufferedReader br = new BufferedReader(isr);
But when I read the output from PianoBar via this reader, it spits out the first line of PianoBar ("Welcome to pianobar (2013.05.19-win32)! Press ? for a list of commands."), then it spits out the next line ("[?] Email:"). Then it just hangs.
Obviously, it is waiting for the user to input their email. But no matter what I try, I can't get my Java program to write the email to the PianoBar process when prompted - it just hangs as soon as it reads out the last character.
Is it possible to do what I am trying to do? I thought it would be an easy thing to look for on the internet, but I haven't been able to find anything. All I want is an easy way to write to the external process when prompted. Seems like this should be easy...
You may use the following code snippet to get working:
String s;
//s = email
BufferedWriter bufferedwriter = new BufferedWriter(new OutputStreamWriter(pianoBar.getOutputStream()));
bufferedwriter.write(s);
bufferedwriter.flush();
Done!
Remember to surround the code block with appropriate try/catch
Related
is it possible to send a command to an running Process like in the example below?
And how would you do that?
Process p = pb.start();
Most possibly not what you are wanting to achieve, but yes, you can communicate to a running Process with Process.getOutputStream()
For processes that read and write to the command line use p.getOutputStream() to send data to the process and p.getIntputStream() to read data from the process. For GUI processes you need native code to send messages depending on the operating system.
Edit:
Example code for processes that are reading/writing to the console:
Process process = pb.start();
// process stdout
Scanner stdout = new Scanner(
new BufferedReader(
new InputStreamReader(process.getOutputStream())));
// process stdin
PrintWriter stdin = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(process.getInputStream())), true);
// sending commands to the process
stdin.println("command1");
stdin.println("command2");
stdin.println("command3");
// reading process output
while (stdout.hasNextLine()) {
System.out.println("Process output: " + stdout.nextLine());
}
I have a minor Problem with a small Project I'm trying to do.
I'm trying to use a Java-Program to call a Python-Script.
Java:
ProcessBuilder pb = new ProcessBuilder("python3", "tmp.py");
process = pb.start();
OutputStream stdin = process.getOutputStream();
InputStream stderr = process.getErrorStream();
InputStream stdout = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(stdout));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));
writer.write("example" + "\n");
String output = reader.readLine();
Python-Script tmp.py (example):
import sys
sys.stdin.readline()
print("Hello World")
It wont terminate, seemingly because sys.sdin.readline() isnt catching any input and if I remove this line it terminates just fine.
(stderror was empty too)
I tried different things to fix this but nothing seems to work.
I would really appreciate any advice. Thanks in advance.
(Update: I tried to modify the Java-Program to access a .jar File instead of a Python-Script but the same error occurs here to. Using the Python Method subprocess.Popen() to access the Script however works just fine.)
Make sure you start python unbuffered with -u flag:
Force the binary layer of the stdout and stderr streams (which is
available as their buffer attribute) to be unbuffered. The text I/O
layer will still be line-buffered if writing to the console, or
block-buffered if redirected to a non-interactive file.
Edit
I recommend reviewing the buffering all the same. The python unbuffered is a common one, but you possibly still have some buffering. Make sure you flush java writer, writer.flush().
I'm trying to start some .jar inside an .jar using this code: (I'm trying with craftbukkit server right know)
Runtime rt = Runtime.getRuntime();
Process p = rt.exec("java -jar craft.jar");
BufferedReader out = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedWriter in = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
this.running = true;
while(this.running){
String line;
if((line = out.readLine()) != null){
System.out.println(line);
}
}
The problem is, it work for a moment, but after a while it stops outputting or just print '>' as show in the image below. How can I fix this? **Plus, Which is the correct way to send commands to the bukkit server?
Thanks!
When using a Process in Java, it is crucial to read stdout and stderr in two independend threads (your while loop). Otherwise the child process can lock up waiting for the filled buffer to be drained.
With Java 7 you can actually redirect stderr to stdout, and possibly redirect the resulting stream to the parents stdout. With older versions you need to attach the seperate threads.
Besides: you should not use the "single string" variant of exec, but specify the args as arrays. This is safer (less vulnerable to parsing problems).
(But I am not sure if this is your actual problem. Maybe you should dump the error stream and see if it helps)
I do it like that:
#Override
public void run(){
// ...
BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream())); //of course proc is an instance of Process, and it's set up
while(true){
String line = stdInput.readLine();
if(line == null) break; //this is essential, when process terminates, line gets null
System.out.println(">"+line);
}
// ...
}
Give it a try.
(Technically it's similiar how you did, but it works for me so i share it)
I have a command line Java program which i unfortunately cannot modify for certain integrity reasons, I am providing a GUI for this program and i got it all covered except that i am unable to provide notifications about completion of processes to the user as the program prints data to command line using System.out.println() , I designed the UI using net beans and it resides in a separate file , so how can i do this..?
Are you using Runtime.exec to execute the program? Then you can get the output stream as well like this:
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("java yourOtherProgram.jar");
InputStream stdin = proc.getInputStream();
If you're calling some method directly, you could redirect System.out like this:
PrintStream out = ...;
PrintStream err = ...;
System.setOut(out);
System.setErr(err);
ThatOtherProgram foo = new ThatOtherProgram();
foo.main(new String[0]);
EDIT
You could then use the Scanner to scan the input and do something with it.
I want to call an "interactive" Perl script from a Java program. Just for the clarity, the other way around (from Perl to Java) is not good for me.
The script is interactive in the sense that it requires a small configuration dialog with the user. For example, calling the script in cmd.exe would lead to a dialog like:
Do you want to overwrite the old settings? [yes,no (default=no)]
and the user should choose between writing yes, no or nothing at all in the command line.
And depending on the user choice another message would appear: "Do you want to...." and the user will respond etc etc. I think you got the picture.
My question is how can I have the same dialog with the user when the script is called in a Java program? I mean, how can I capture the script's questions to the user, show them to user and then send the user's answer (got in the Java program) to the script?
A simple Runtime.getRuntime().exec() doesn't work in this case.
Hope I expressed clear enough the question.
Thank you for your help!
You must use getInputStream/getOutputStream methods to get access to stdin and stdout of perl stript. You can read and write to these streams to simulate user's behavior
OutputStream stdin = null;
InputStream stderr = null;
InputStream stdout = null;
Process process = Runtime.getRuntime ().exec ("...");
stdin = process.getOutputStream ();
stderr = process.getErrorStream ();
stdout = process.getInputStream ();
// "write" the parms into stdin
String line = "data\n";
stdin.write(line.getBytes());
stdin.flush();
stdin.close();
// clean up if any output in stdout
BufferedReader brCleanUp =
new BufferedReader (new InputStreamReader (stdout));
while ((line = brCleanUp.readLine ()) != null) {
//System.out.println ("[Stdout] " + line);
}
brCleanUp.close();
// clean up if any output in stderr
brCleanUp =
new BufferedReader (new InputStreamReader (stderr));
while ((line = brCleanUp.readLine ()) != null) {
//System.out.println ("[Stderr] " + line);
}
brCleanUp.close();
This is a job for Expect. In Java: ExpectJ, expect4j
If (1) your call is from Java to Perl, and (2) you are not parsing the Perl script itself, why not use a JOptionPane.showConfirmDialog() from the Java code? Shouldn't be a big deal if a Yes/No is all your are getting from the script. Whatever you are printing to display to the user can be included in that confirm dialog as a plain ASCII text, too.