Hi im building a Java GUI for a c++ program and i'm kinda stuck with the ProcessBuilder that calls my exe file.
I made this little program in C++ just to test this ProcessBuilder thing and see if i could control the I/O streams:
#include <cstdlib>
#include<stdio.h>
int main(int argc, char** argv) {
int testInteger;
int a = 1;
while (a==1){
printf("Enter an integer: ");
scanf("%d",&testInteger);
if (testInteger == 0){
printf("Quitting program!");
return 0;
}else{
printf("You entered the number = %d\n",testInteger);
}
}
return 0;
}
My Java code is as follows:
public static void main(String[] args) throws InterruptedException, IOException{
ProcessBuilder pb = new ProcessBuilder("./i_o_test");
Process process = pb.start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line=br.readLine()) != null){
System.out.println(line);
}
}
The code doesn't prompt any error and just hangs on the while loop. It does not print anything.
This code works just fine with commands like "echo", so i don't know what im doing wrong here.
(if you guys have a better suggestion for taking control of the i/o streams in a c++ exe process from Java other than ProcessBuilder, im all ears)
Thanks in advance,
Maarc~
BufferedReader#readLine() blocks until a complete line is available, indicated by receiving a newline character.
Your C++ code prints a prompt but without a newline. This results in readLine() not returning, resulting in the behavior you are seeing. If you want the Java and C++ code to interact you must define a "protocol" to communicate when a message is complete and ready to be acted on. This can be as simple as a newline, or more complex if your needs are different. It's really up to you, but if you are dealing with some existing C++ program and want to control it from Java you have to be prepared to deal with it.
For example, if the C++ program prompts without newlines and you can't change that you might have to look for the colon : at the end of the prompt string instead. This would mean the Java code cannot use readLine() and must process input one character at a time.
Related
Whilst building an wrapper for an console application I came across this weird issue where the Input Stream connected to the output (stdout) of the external process is completely blank until the external process exits.
My code as below:
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
public class Example{
public static void main(String args[]) throws IOException{
File executable = ...
ProcessBuilder pb = new ProcessBuilder(executable.getCanonicalPath());
pb.redirectErrorStream(true);
Process p = pb.start();
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(), Charset.forName("UTF-8")));
String line;
while((line = br.readLine()) != null){
System.out.println(line);
}
}
}
I've tried several variants of reading from the input stream and all resulted in the same behavior.
I've tried:
CharBuffer charBuf = CharBuffer.allocate(1000);
InputStreamReader isr = new InputStreamReader(p.getInputStream(), Charset.forName("UTF-8"));
while(isr.read(charBuf) != -1){
System.out.print(charBuf.flip().toString());
}
and
byte[] buf = new byte[1000];
int r;
while((r = p.getInputStream().read(buf)) != -1){
System.out.print(new String(buf, 0, r));
}
all to no avail.
Somewhere along the line the output from the external process is being buffered (indefinitely) and I can't really figure out where. Loading the process from the command line seems to work fine where I see output coming out instantaneously. The strangest part is where the fact that the termination of the external process results in a flood of all the "buffered" output at once (a lot of stuff).
Unfortunately I don't have access to the source of the external process but given that it writes to stdout fine when in a console shouldn't really make a difference there (as far as I know).
Any ideas are welcome.
Edit:
One answer recommended me to rewrite the reader for the output and error streams to run on a separate thread. My actual implementation is doing that! And yet the problem still exists. The code posted above is a SSCCE of my actual code condensed for readability purposes, the actual code involves a separate thread for reading from the InputStream.
Edit 2:
User FoggyDay seems to have provided the answer which defines how the behavior of output buffering change when outputting between console and non-consoles. Whilst processes which detect that they are writing to a console use line buffering (buffered flushed every new line), writing to non-consoles (everything that it detects to not be a console) may be fully buffered (to a size of something like 8K). If I make the external process spam (8K of lorem ipsum in a for loop) output does indeed appear. I guess my question now is how to make my java program trigger line buffering on the external process.
To your question "how to make my java program trigger line buffering on the external process":
On Linux you can use the "stdbuf" program (coreutils package): stdbuf -oL your_program program_args
You only need to change stdout since stderr is unbuffered by default. The man page of setlinebuf gives additional background information if you're interested: http://linux.die.net/man/3/setlinebuf
Some software checks if it is writing to a terminal and switches behavior to unbuffered output. This could be a reason, why it works in the terminal. Pipe the output to cat and see if the output still appears immediately.
Another reason could be that the program is waiting for input or a close of its stdin before it does something, although this does not really match the symptoms described so far.
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.
I am using libdmtx which comes with a command line utility which reads the image files for ECC200 Data Matrix barcodes, reads their contents, and writes the decoded messages to standard output. I have used command line utility in my java program on linux platform. I am using ubuntu linux. I have installed the libdmtx on my linux machine. and when I invoke the command
dmtxread -n /home/admin/ab.tif
on linux terminal it gives the decoded value of barcode in image immediately i.e within 15 seconds.
but when I am going to invoke this same command for same file using my java program the program takes huge time i.e average 16 minutes for the same command and same file above.
Following is my java code which invokes the above command
public class Test {
public static void main(final String[] args) throws IOException, InterruptedException {
//Build command
List<String> commands = new ArrayList<String>();
commands.add("dmtxread");
commands.add("-n");
commands.add("/home/admin/ab.tif");
System.out.println(commands);
//Run macro on target
ProcessBuilder pb = new ProcessBuilder(commands);
pb.redirectErrorStream(true);
Process process = pb.start();
//Read output
StringBuilder out = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null, previous = null;
while ((line = br.readLine()) != null){
System.out.println(line);
}
//Check result
if (process.waitFor() == 0)
System.out.println("Success!");
System.exit(0);
//Abnormal termination: Log command parameters and output and throw ExecutionException
System.err.println(commands);
System.err.println(out.toString());
System.exit(1);
}
}
I want to ask the experts that
Please can anyone explain me why java program takes such big time to invoke a simple command which will be get invoked withing 15 seconds if that command is directly run on command prompt.
Please can anyone tell me the solution to reduce this time.
I guess the program is taking this so much time because of JVMs internal thread which is invoking the process. Is my guess is right? If yes then how could I overcome to this problem.
Please guide me to solve this problem. Thanks You!
I want to return the same text that is returned when I manually type a command into the cmd prompt in Windows. Here is an example that does not work.
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
String g = "";
Runtime.getRuntime().exec(new String[] {"ipconfig", g});
System.out.println(g);
}
}
I don't know if I should be looking into Runtime.getRuntime()exec because the way I understand the api ( http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Runtime.html ) is that of all of the exec examples, none return a string. The return value (if I understand right) on some is actually a 'process' which I can only guess means nothing gets returned, but the process is started. I used ipconfig in the example, but I actually need to run various diagnostic commands and analyze the string (which I have referred to as the 'cmd prompt').
To capture the output of the command, you can use this:
Process p = Runtime.getRuntime().exec(new String[] {"ipconfig", g});
InputStream s = p.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(s));
String temp;
while ((temp = in.readLine()) != null) {
System.out.println(temp);
}
Please not that the readLine() method will block until it reads an input or the process is terminated.
The Java String is immutable, meaning that the "" referenced by g will never change. No code that doesn't do an assignment of g will ever print something other than the empty string to System.out.
Rather than using Runtime.exec, I recommend you use the Commons-Exec library from the Apache Commons project. It provides a much more reliable means of executing external applications (passing the arguments reliably and preventing such things as an unread output stream locking up the program).
You can capture the command output using the PumpStreamHandler and an input stream of your choice.
If you look at the javadoc link you've already posted, you'll see that Runtime.exec() returns a Process object, and the Process class has a method getOutputStream() to get at the standard output stream of the new process.
I have a python application which I cant edit its a black box from my point of view. The python application knows how to process text and return processed text.
I have another application written in Java which knows how to collect non processed texts.
Current state, the python app works in batch mode every x minutes.
I want to make the python
processing part of the process: Java app collects text and request the python app to process and return processed text as part of a flow.
What do you think is the simplest solution for this?
Thanks,
Rod
I don't know nothing about Jython and the like. I guess it's the best solution if you can execute two programs without executing a new process each time the Java app needs to transform text. Anyway a simple proof of concept is to execute a separate process from the Java App to make it work. Next you can enhance the execution with all that tools.
Executing a separate process from Java
String[] envprops = new String[] {"PROP1=VAL1", "PROP2=VAL2" };
Process pythonProc = Runtime.getRuntime().exec(
"the command to execute the python app",
envprops,
new File("/workingdirectory"));
// get an outputstream to write into the standard input of python
OutputStream toPython = pythonProc.getOutputStream();
// get an inputstream to read from the standard output of python
InputStream fromPython = pythonProc.getInputStream();
// send something
toPython.write(.....);
// receive something
fromPython.read(....);
Important: chars are NOT bytes
A lot of people understimate this.
Be careful with char to byte conversions (remember Writers/Readers are for chars, Input/OutputStreams are for bytes, encoding is necesary for convertir one to another, you can use OuputStreamWriter to convert string to bytes and send, InputStreamReader to convert bytes to chars and read them).
Look into Jython - you can run Python programs directly from Java code, and interact seamlessly back and forth.
Use ProcessBuilder to execute your Python code as a filter:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class PBTest {
public static void main(String[] args) {
ProcessBuilder pb = new ProcessBuilder("python", "-c", "print 42");
pb.redirectErrorStream(true);
try {
Process p = pb.start();
String s;
BufferedReader stdout = new BufferedReader (
new InputStreamReader(p.getInputStream()));
while ((s = stdout.readLine()) != null) {
System.out.println(s);
}
System.out.println("Exit value: " + p.waitFor());
p.getInputStream().close();
p.getOutputStream().close();
p.getErrorStream().close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Expose one of the two as a service of some kind, web service maybe. Another option is to port the python code to Jython
One possible solution is jpype. This allows you to launch a JVM from Python and pass data back and forth between them.
Another solution may be to write the Python program as a filter (reading data from stdin and writing result to stdout) then run it as a pipe. However I do not know how well Java supports this - according to the Sun docs their concept of pipes only supports communication between threads on the same JVM.
An option is making the python application work as a server, listens for request via sockets (TCP).