Java Process causing python script JSON error - java

I have a Java program that manages data. When it wants to create a report from said data it does so via saving a JSON file with the relevant data for the report and then setting off the python script via the use of a ProcessBuilder object. I'm however having a weird error should I try and extract data from the output of the python script.
ProcessBuilder pythonProcess = new
ProcessBuilder("python","ReportingTool.py");
pythonProcess.directory(new File("invoice_python_files\\"));
Process pythonRunnable =pythonProcess.start();
/*
BufferedReader outputReader = new BufferedReader(new
InputStreamReader(pythonRunnable.getInputStream()));
BufferedReader errorReader = new BufferedReader(new
InputStreamReader(pythonRunnable.getErrorStream()));
String line =null;
System.out.println("<ERROR>");
while ( (line = errorReader.readLine()) != null)
System.out.println(line);
System.out.println("</ERROR>");
System.out.println("<Output">)
while ( (line = outputReader.readLine()) != null)
System.out.println(line);
System.out.println("</OUTPUT>");
*/
This works fine and produces the report as expected (without the input stream code). If I then uncomment the code I get an error from the python script.
File "C:\Users\o.cohen\AppData\Local\Programs\Python\Python36-
32\lib\json\decoder.py", line 357, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
I don't understand how the java process is causing the error and more importantly how to fix it. Below is the code that causes the error (specifically the last line:
with open("InvoiceMakerDoc.json") as json_file:
json_data=json_file.read()
decoded_data =json.loads(json_data)

Your java application need to wait till completion of python job first. Hence you need to add pythonRunnable.waitFor() before reading the input stream.
Process pythonRunnable =pythonProcess.start();
pythonRunnable.waitFor();

Managed to fix it.
The program was writing to the JSON file before it set the python program off and the FileWriter object hadn't been closed causing the issue.

Related

Using ProcessBuilder to execute Linux Command and getting NULL from reader.readLine() although line count is 102

I get a NULL when trying to print the lines from the InputStream.
The line count does return a value and the file I am opening does contain the same amount of lines.
reader.readLine() returns NULL.
reader.lines().count() does return the correct amount of lines in the file...
So it leads me to believe that:
The command was executed successfully.
The file was opened and read successfully.
The correct Stream is being used. i.e. process.getInputStream()
I am trying to use Java to run a linux command that will open a file which is located on the server and print it out / log it to my log file.
I've tried using ProcessBuiler and Runtime.getRuntime.exec(). Both yield the same result... a NULL on reader.readLine().
Some posts suggested using the process.getOutputStream. Which returned a 0 line count and null lines.
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command("sh", "-c", "cat chris.txt");
processBuilder.directory(new File("/opt/tmp/FOLDER_NAME"));
Process process = processBuilder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
logger.info("######### {}", line);
}
I am expecting to get the contents of my file printed in my log file.
I am getting a NULL on the reader.readLine() object.
A null return value from readLine() means that you have reached the end of the stream. Thus your process does not produce any output.
In case the file actually has some content, the most likely reason for no output is that your sub-process failed. For example because it could not find the shell, could not find the file, the file was not accessible, ...
Check the return value of process.waitFor(). If this is anything else but 0 then there was a problem. You may also want to capture the stderr of your process since that contains potential error messages. An easy way to do that is to redirect the error stream to the output stream using ProcessBuilder.redirectErrorStream(true).
I've found the issue...
Seems that I was using up the stream by doing a line count prior to using the lines.
A comment on another post helped me find this...
"The while and the for both behave essentially the same way; the reason why your while never "returned" is probably due to your "exhausting" the stream in the countlines() method."

Get STDOUT from Runtime.getRuntime().exec() line-by-line rather than all at once

I'm executing a script from Java with the following code.
try (BufferedReader input = new BufferedReader(new InputStreamReader(Runtime.getRuntime()
.exec("ruby test.rb").getInputStream()))) {
String line = null;
while ((line = input.readLine()) != null) {
System.out.println("Got line: " + line);
}
}
Where test.rb is simply:
puts "one"
sleep 1
puts "two"
The problem is that all of the input arrives in the BufferedReader at the same time. There should be a 1 second delay between the two lines. Is there a way to flush the Inputstream after every line in the script?
What I'm trying to accomplish
I want to call some Ruby scripts from a Java GUI and have the output of the script show up incrementally in a textpane. Using the code above, STDOUT from the script shows up in the textpane all at once when the script terminates (and the Inputstream is presumably flushed).
Edit:
The issue was that Ruby was buffering STDOUT. Fixed by $stdout.sync = true.
Have you tried Thread.sleep(1000) after System.out.println(). You must catch some InterruptedException. Your editor will tell you for sure.

Trying to use xcopy within Java to copy a folder

I'm trying to execute a command line to copy a folder, but nothing happens . I tried the same command from the command line and it worked fine.
code
Runtime rt = Runtime.getRuntime();
String line;
try {
Process pr = rt.exec("xcopy //E //I notts nots2");
InputStreamReader mInputStreamReader = new InputStreamReader( pr.getInputStream());
BufferedReader input = new BufferedReader( mInputStreamReader );
while ( (line = input.readLine()) != null)
System.out.println(line);
} catch (IOException e) {
ted=ted+1;
}
1) pr.getInputStream() is not enough because it will not read the error output encountered during the process execution.
You should also read the error stream : pr.getErrorStream().
2) You should specify the working directory of the process otherwise the process inherits the working directory of the current process.
For example :
Process pr = rt.exec("xcopy //E //I notts nots2", null, new File("yourWorkingDirToRunTheProcess"));
Look at the answer to this question. It explains how to consume the standard output and standard error streams of the process.
You should also consider copying files using java API methods instead of running an external process. One reason being that your command (xcopy) won't work on anything but Windows. Another reason is that running an external process is much more error prone than using standard API methods.

Failing to redirect standard output in Java

I am attempting to redirect the console output of a Java library to a JTextArea in my application. The library in question is JPL, a bridge between Java and SWI-Prolog (though I doubt this has much relevance conceptually).
Here is my code:
PrintStream out = new PrintStream(new MyOutputStream(), true, "UTF-8");
System.setOut(out);
System.setErr(out);
System.out.println("This text is successfully redirected.");
Hashtable<String, Term> solutions[] = Query.allSolutions("append([1],[2],[1,2])");
When I run this code, the string "This text is successfully redirected" is redirected to my PrintStream as expected. However, the last line of the above snippet generates some text output which is still printed at the Java console instead of in my PrintStream.
What could the method allSolutions(String) be doing so that its output is not redirected? Could it be the fact that it calls an OS process that generates the output (it does call the swipl process)? If so, can I redirect its output without modifying the JPL code?
Yes, your assumption is correct: the process being executed is printing directly to the console. What you can do is capture the output of that process and pass it to your PrintStream as shown here by #StijnGeukens: (copy pasted code follows)
String line;
Process p = Runtime.getRuntime().exec(...);
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
System.out.println(line);
}
input.close();
But that's only if you actually have access to the internals of allSolutions.
I do not know a way of capturing any other output, I'm afraid.

shell process java synchronization

I want to run a shell script from a java program. This shell script invokes a system library which needs a big file as resource.
My java program calls this script for every word in a document. If I call this script again and again using Runtime.exec() the time taken is very high since the resource loading takes lot of time.
To overcome this I thought of writing the shell script as follows (to make it run continuously in background ):
count=0
while count -lt 10 ; do
read WORD
//execute command on this line
done
I need retrieve the output of the command in my java program and process it further.
How should I code the I/O operations for achieving this task?
I have tried writing words in to the process's output stream and reading back output from process's input stream. But this does not work and throws a broken pipe exception.
try {
parseResult = Runtime.getRuntime().exec(parseCommand);
parsingResultsReader = new BufferedReader(new InputStreamReader (parseResult.getInputStream()));
errorReader = new BufferedReader(new InputStreamReader (parseResult.getErrorStream()));
parseResultsWriter = new BufferedWriter(new OutputStreamWriter((parseResult.getOutputStream())));
} catch (IOException e) {
e.printStackTrace();
}
parseResultsWriter.write(word);
parseResultsWriter.flush();
while ((line = parsingResultsReader.readLine()) != null) {
// capture output in list here
}
Kindly help with this issue
//execute command on this line
Is this command a separate program? Then it will be launched for every word, so you'll get rid of only shell process which is lightweight anyway.
You have to learn how to run the heavyweight command for many words at once.

Categories

Resources