Java 8 here. How does one read the data in Process#getOutputStream() into a String? I am trying to run a process from inside Java and hook/capture its STDOUT.
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec("consul -v");
String capturedOutput;
OutputStream os = proc.getOutputStream();
capturedOutput = howDoIConvert(os); // <---- ???
Looking for the exact code here (not something vague like baos.toString(codepage). Also interested if I need to close() anything politely.
You read the data from inputStream not from outputStream.
OutputStream is used to pass data to the process.
There are two basic input streams for Process. One is for standard input and can be retrieved with getInputStream() the other is for errors and can be retrieved with getErrorStream()
From javadoc of getInputStream():
Returns the input stream connected to the normal output of the
subprocess
and from getErrorStream()
Returns the input stream connected to the error output of the
subprocess.
Note on streams: from the java program perspective a Process is an external program. When you need to add some input to the external program you write from java to that program (so the output of java program is the input of Process). Instead if the external program writes something you read it (so the output of Process is the input for the java program).
Java Data direction External Process
_____________________________________________________________
write to OutputStream ------------> read from InputStream
read from InputStream <------------ write to OutputStream
Related
I've stored my python code in file and then input is passed through input.txt.
String rollno="13F127";
String file="add";
Process p = Runtime.getRuntime().exec("C:\\Python34\\python C:\\Users\\Raga\\Documents\\"+rollno+"\\"+file+".py < C:\\Users\\Raga\\Documents\\"+rollno+"\\input.txt");
When I run it using jsp file, it takes long time to load and output didnt come. Please help me with this.
I've read this process output using buffered and input reader.
stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
Please help me with this!
Do not use redirections (<, >, or |) with exec!
The redirections are read and translated by the interactive shells (here cmd.exe) where they read a command from their standard input. The shell then opens the relevant files and calls the program with redirected standard streams.
exec just does this last part, and passes the < ...input.text as two arguments to the Python program... that do not processes them and also passes them to the script that do not process them either! So the child tries to read on standard input, and keeps waiting here.
So you should:
use ProcessBuilder which according to Runtime javadoc is now the preferred way to start a process with a modified environment
redirect input stream for the subprocess to the file
More or less:
ProcessBuilder pb = new ProcessBuilder("C:\\Python34\\python",
"C:\\Users\\Raga\\Documents\\"+rollno+"\\"+file+".py");
pb.redirectInput(Redirect.fromFile("C:\\Users\\Raga\\Documents\\"+rollno+"\\input.txt"));
Process p = pb.start();
How do I pipe a file into the stdin of a process using ProcessBuilder? The program I am reading the stream from is written in C, but I do not know anything else about it.
Here is the relevant java:
ProcessBuilder pb = new ProcessBuilder("./program").inheritIO();
Process p = pb.start();
DataInputStream din = new DataInputStream(new FileInputStream("./my-file.txt"));
byte[] dinBytes = new byte[din.available()];
din.readFully(dinBytes);
din.close();
OutputStream os = p.getOutputStream();
os.write(dinBytes);
os.close();
int rc = p.waitFor();
System.out.println("RC: " + rc);
Which returns the following error:
java.io.IOException: Stream closed
at java.lang.ProcessBuilder$NullOutputStream.write(ProcessBuilder.java:434)
at java.io.OutputStream.write(OutputStream.java:116)
at java.io.OutputStream.write(OutputStream.java:75)
at Test.main(Test.java:14)
$ input in flex scanner failed
The cause for your error is the call to .inheritIO() when you build the process. This causes all the process's standard file descriptors to be inherited from the Java process. The documentation says:
This is a convenience method. An invocation of the form
pb.inheritIO()
behaves in exactly the same way as the invocation
pb.redirectInput(Redirect.INHERIT)
.redirectOutput(Redirect.INHERIT)
.redirectError(Redirect.INHERIT)
And the documentation for redirectInput(Redirect) says:
If the source is Redirect.PIPE (the initial value), then the standard input of a subprocess can be written to using the output stream returned by Process.getOutputStream(). If the source is set to any other value, then Process.getOutputStream() will return a null output stream.
So, basically, the default is that there is a pipeline between the Java process and the built process, so that you can push in data from your program to the process. But you released the standard input of the process from the pipe and let it wait for input from the user console, but then you tried to treat it as if it's still part of the pipe, and get your end of the pipe in order to push data inside. You get a null output stream, and as soon as you try to put something in it, you get an exception.
So you shouldn't make that call. And since you want input from a text file, the easiest thing to do would actually be to redirect that input stream to the file directly. Again, redirecting breaks the pipe - but you won't need it because the redirection actually does what you need:
// Take input from a file, output and error go to user console
pb = new ProcessBuilder("./program")
.redirectInput(new File("./my-file.txt"))
.redirectOutput(Redirect.INHERIT)
.redirectError(Redirect.INHERIT);
Process p = pb.start();
int rc = p.waitFor();
An alternative method, in case you want to pipe in more than one file, is to keep the pipe to the process standard input around, but copy the files using Files:
pb = new ProcessBuilder("./program")
.redirectOutput(Redirect.INHERIT)
.redirectError(Redirect.INHERIT);
Process p = pb.start();
OutputStream os = p.getOutputStream();
Files.copy( Paths.get("./my-file-1.txt"), os );
Files.copy( Paths.get("./my-file-2.txt"), os );
// more files
os.close();
int rc = p.waitFor();
Regarding the DataInputStream: it is a type of InputStream used for processing binary data that was written from a DataOutputStream - with ints, doubles etc. written in binary form. Of course, like any InputStream, you can read bytes from it as-is. But for that, you don't really need to wrap it in a DataInputStream.
how do i get output from a batch file, but also give input to a batch file?
My Q. is self-explanitory.
Like i made a small code to run a batch file:
Process process = Runtime.getRuntime().exec("(my file)");.
but now what?
You can get input and output streams from the process using the corresponding getter methods.
Edit:
getInputStream()
and
getOutputStream()
I have java cde that jars class files together:
List<String> args = new ArrayList<String>();
String path = FileSystemUtils.JavaBin() + "\\jar.exe";
args.add(path);
args.add("-cfv");
args.add(jarName);
args.addAll(FileSystemUtils.getAllFiles(directory, ".class"));
ProcessBuilder pb = new ProcessBuilder(args);
File wd = new File(directory);
pb.directory(wd);
Process p = pb.start();
//Waiting for process to exit
p.waitFor();
int res = p.exitValue();
Tis code works great.
However, on some computers - not on all of them, when there are 7+ files, the p.waitFor(); never return, even though the jar was created.
Looking at the task manager, jar.exe really did not terminate.... what can be the cause?
running the same command manually from the command line exits immediately.
This seems very weird. Does someone have any hint?
Found the solution myself.
Apparently if you use ProcessBuilder.start in Java to start an external process you have to consume its stdout/stderr, otherwise the external process hangs.
This is beacuase OS creates a pipe.
All Unix like OSs and Windows behave the same in this regard: A pipe with a 4K is created between parent and child. When that pipe is full (because one side isn't reading), the writing process blocks.
It seems that when there are 7+ files the jar.exe consume 4K, nad then stuck.
Javadoc of process:
By default, the created subprocess does not have its own terminal or
console. All its standard I/O (i.e. stdin, stdout, stderr) operations
will be redirected to the parent process, where they can be accessed
via the streams obtained using the methods getOutputStream(),
getInputStream(), and getErrorStream(). The parent process uses these
streams to feed input to and get output from the subprocess. 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 am trying to use the ProcessBuilder to make java communicate with an external program (Prolog).
I understand how to set the environment variables and have done this.
But I don't understand how I communicate with the process, how I give an input to it, how I get the output from it, how the errors are handled. I believe I need to use an input stream the get the output from prolog, an input stream for the errors from Prolog, and an output stream to give prolog the input. Can somebody tell me how I use these streams to communicate with the program?
Here is what I have so far (let me know if I'm thinking wrong at some point)
ProcessBuilder pb = new ProcessBuilder("gprolog");
//Enviroment variable to disable the gui for prolog
pb.environment().put("LINEDIT", "gui=no");
InputStream in = pb.getInputStream();
InputStream err = pb.getErrorStream();
OutputStream out = pb.getOutputStream();
pb.start();
How do I give a command to prolog after this?