I'm trying to use ProcessBuilder to execute a simple python script from CMD, which prints to the command line, then have that text read into Java and outputted through System.out.println() in netbeans. My issue is the BufferedReader seems to pause at .readLine() then output the text in bulk once the py script has stopped running, as opposed to outputting live.
My process is as follows:
[execute python script]
Executors.newSingleThreadExecutor().execute(this::TEST);
[run execution]
public void TEST(){
try {
ProcessBuilder py = new ProcessBuilder("cmd", "/C", "C:\\Users\\Documents\\TEST.py");
String readLine;
Process launch = py.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(launch.getInputStream()));
while((readLine = reader.readLine()) != null){
System.out.println(readLine);
}
} catch (IOException ex) {Logger.getLogger(Template.class.getName()).log(Level.SEVERE, null, ex);}
}
[here is the python script i wish to run and read live]
import Tkinter, tkFileDialog, tkMessageBox
root = Tkinter.Tk()
root.withdraw()
root.resizable(width=Tkinter.TRUE, height=Tkinter.TRUE)
root.geometry('{}x{}'.format(400,600))
print("hello1\n")
print("hello2\n")
print("hello3\n")
print("hello4\n")
print("hello5\n")
tkMessageBox.showinfo("Complete!", "testing")
print("hello6\n")
print("hello7\n")
print("hello8\n")
print("hello9\n")
print("hello10\n")
tkMessageBox.showinfo("Complete!", "testing")
Thanks!!!
First: Your command does not do anything. It is cmd /C C:\Users\Documents\TEST.py which does nothing but tell you that C:\Users\Documents\TEST.py is not a command. You would need to call cmd /C start C:\Users\Documents\TEST.py for it to do something.
Still this won't make your code work. The problem here is that you are invoking a cmd in there you start a python process. When you now grab the input stream you are getting the cmd input stream which is not the one you are looking for.
In order to get it to work invoke python directly by calling python C:\Users\Documents\TEST.py. Make sure python is in your PATH for this to work.
Your code should then look something like this:
try
{
ProcessBuilder py = new ProcessBuilder("python", "C:\\Users\\Documents\\TEST.py");
String readLine;
Process launch = py.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(launch.getInputStream()));
while ((readLine = reader.readLine()) != null)
{
System.out.println(readLine);
}
}
catch (IOException ex)
{
Logger.getLogger(Template.class.getName()).log(Level.SEVERE, null, ex);
}
This gives you exactly the result you were looking for.
A common problem can be that you did not flush your python std out. I recommend adding
import sys
# your code here...
sys.stdout.flush()
to your code to flush your python output.
Related
I'm trying to run ffmpeg in Java using ProcessBuilder. I'm on Windows. It works fine. But not sure why it's much slower than when I just run the same command in command prompt or PowerShell.
Why is it? Is there any ways to increase the speed?
processBuilder.command("C:\\Windows\\System32\\cmd.exe", "/c","ffmpeg.exe", "-y", "-i", video,"-vf","scale=720:-1","out.mp4");
processBuilder.redirectErrorStream(true);
try {
process = processBuilder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line="";
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (Exception e) {
System.err.println("Error in processBuilder. ");
}
You have two starts, delete the first or the redirect will not work:
process = processBuilder.start();
If your sub-process is quite verbose the problem may simply be System.out.println() as multiple line output to some Windows cmd / terminals can be exceptionally slow. You can verify if this is the case by commenting out the print, or capture to File based output before start:
processBuilder.redirectOutput(new File("stdout.log"));
Don't forget to add status check at the end and cross check rc with ffmpeg documentation:
int rc = process.waitFor();
We can use Jython to implement python in java, but I dont want to go for that approach, what I am looking for is using command line utility and fire python command to execute the code and get the console output in java code.
python Main.py < input.txt
I used above command in terminal, it works there, giving me output, but unable to get the output in java code.
Note: Main.py and input.txt and java code in the same folder
What I am doing wrong in java code?
Here is Sample java code which I am calling in order to execute external python code
try {
Process process = Runtime.getRuntime()
.exec("python Main.py < input.txt");
process.waitFor();
System.out.println(process);
StringBuilder output
= new StringBuilder();
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
System.out.println("here");
int exitVal = process.waitFor();
if (exitVal == 0) {
System.out.println("Success!");
System.out.println(output);
} else {
System.out.println("Process failed");
}
} catch (Exception e) {
// TODO: handle exception
System.out.println(e);
}
Here is a sample python code:
x = input();
y = input();
print(type(x));
print(type(y));
print(x + y);
here is a sample input file which I am passing as a input to the python code
30
40
As sandip showed, executing a command in java is not the same as running commands through BASH.
At first I tried to execute
bash -c "python Main.py < input.txt" (through java).
For some reason this didn't work, and even if it did its not a great solution as its dependent on the system its running on.
The solution I found to work was by using ProcessBuilder to first make the command, and redirect its input to a file. This allows you to keep the python code unchanged, and for me at least, give the same result as just running the BASH command.
Example:
ProcessBuilder pb = new ProcessBuilder("python3","Main.py");
//Make sure to split up the command and the arguments, this includes options
//I only have python3 on my system, but that shouldn't affect anything
pb.redirectInput(new File("./input.txt"));
System.out.println(pb.command());
Process process = pb.start();
//The rest is the exact same as the code in the question
Heres the ProcessBuilder docs for quick reference
java process not accept < symbol to input file in python command.
Instead you can run like this
python file
f = open("input.txt", "r")
for x in f:
print(type(x));
print(x)
java file
Process process = Runtime.getRuntime().exec("python Main.py input.txt");
process.waitFor();
System.out.println(process);
StringBuilder output
= new StringBuilder();
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
System.out.println("here");
int exitVal = process.waitFor();
if (exitVal == 0) {
System.out.println("Success!");
System.out.println(output);
} else {
System.out.println("Process failed");
}
} catch (Exception e) {
// TODO: handle exception
System.out.println(e);
}
and use and same text file.
It should print in console
I have a Java script that starts a new thread to execute a python script using Process builder. The code below currently takes the output from python and displays it in the Java run output and within a JTextArea. BUT, it only does so in bulk, once the py script has finished running. Is there a way to get the output displayed live as it is written out from the py script? Thanks!!!!
public void launchPythonScript() {
try {
ProcessBuilder py = new ProcessBuilder("cmd", "/C", "PythonScriptLocation (C:\\....)",""+Directory(variable needed for py script));
Process launch = py.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(launch.getInputStream()));
String readLine;
StringBuilder JavaOutput = new StringBuilder();
while((readLine = reader.readLine()) != null){
JavaOutput.append(readLine).append(System.lineSeparator());
frame2.consoleOutput.setText(JavaOutput.toString());
System.out.println(readLine);
}
} catch (IOException ex) { Logger.getLogger(Frame1.class.getName()).log(Level.SEVERE, null, ex);}
}
Process InputStream should give you data while the script is running.
You are reading one line at time so if your python script send all data in one single line then you see the output only at the end.
Try to break the output data into multiple lines.
I am calling a bash scrip script from Java.
The script does the following:
cat /home/user/Downloads/bigtextfile.txt | grep 'hello'
This particular command when run command line takes about 1 second to complete on the text file which is 150MB.
When calling the bash script via Java using the following call:
command = "sh /home/user/bashfiletocall"
p = Runtime.getRuntime().exec(command);
The time to complete takes so long I don't wait.
Am I doing something very wrong and if not can you explain the reason for the huge lack in performance?
NOTE: I was running it in Netbeans and this seems to be the problem .. when I ran the file command line it was quick. The performance between execution in netbeans and command line is huge.
Many thanks.
private String executeCommand(String command) {
StringBuilder output = new StringBuilder();
BufferedReader reader = null;
Process p;
try {
p = Runtime.getRuntime().exec(command);
p.waitFor();
reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine())!= null) {
output.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
After starting your process you need start reading from the input stream. Otherwise the buffers are running full and p.waitFor() waits forever.
Javadoc of the Process class:
Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, or even deadlock.
I need to open a command prompt from java code and run some commands on the same and after that I need to read that command prompt output in java code in real time.
I have tried with below code but I was not able to read the cmd prompt display/output in java.
File file = new File("D://Projects/quantum");
Process proc = rt.exec("cmd.exe /c start cmd.exe /k \"ping localhost\"", null, file);
try {
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
StringBuffer buffer = new StringBuffer();
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
Check this out
Process p=Runtime.getRuntime().exec("cmd /c dir");
p.waitFor();
BufferedReader reader=new BufferedReader(new InputStreamReader(p.getInputStream()));
String line=reader.readLine();
This is a very fragile implementation of running a Process.
General tips.
Read and implement all the recommendations of When Runtime.exec() won't.
Once that is done, ignore the fact the article explicitly refers to the Runtime.exec() method and establish the Process using a ProcessBuilder, which makes it easier to implement some of the recommendations of the first linked article.
But even then, break the String command into a String[] arguments of command.