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.
Related
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.
Recently I am trying to write an java application to call SCM.exe to execute the code loading job. However, after I successfully execute the SCM load command via java, I found that I actually cannot really download the code (as using the command line, the password need to be entered after execute the SCM load command). May I know how can I enter this password just after I use the process to run the SCM in java? How can I get the output of the command line and enter something into the command line?
Thanks a million,
Eric
Since I don't know what exactly SCM.exe in your case is, I'm answering only what deals with the input/output redirection requirements in an abstract sense. I assume further that you are calling SCM.exe with whatever parameters it needs through System("...") and this is where you are unable pass any further input (stdin of the called process).
You need, instead, to be able to, upon receiving the request for password, pass it to the stdin of the other process, which is solved by using pipes in the classical sense (since you are presumably on Windows, YMMV). More generally, you are dealing with a very simple case of IPC.
In Java you may find an adequate solution by using ProcessBuilder [1] (never did myself, though -- i'd use things a lot simpler than java for this purpose, but I digress...).
An outline of a solution would be:
call the process, having its input and output being handled as output/input streams from your caller java process.
read the output of your process until you are queried the password
write the password
carry on as needed.
If you need further clarification you may need to give more details about your scenario.
[1] http://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html
public class test {
public static void main(String[] args){
try {
System.out.println("");
String commands = "C:/swdtools/IBM/RAD8/scmtools/eclipse/scm.exe load -d C:/users/43793207/test -i test -r eric-repo";
// load -d C:/users/43793207/test -i test -r eric-repo
test test=new test();
test.execCommand(commands);
} catch (Exception e) {
e.printStackTrace();
}
}
public void execCommand(String commands){
//ProcessBuilder pb = new ProcessBuilder(Command);
//pb.start();
String line;
try {
//Process pp = Runtime.getRuntime().exec(commands);
System.out.println(commands);
Process process = new ProcessBuilder(commands).start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
I've got to write down some java code that runs an external process.
This process gets an input line from stdin and gives an output line on stdout.
The code I wrote is as follows
try
{
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("./" + args[0]);
Process proc2 = rt.exec(c);
int exitVal = proc2.exitValue();
System.out.println("Process exitValue: " + exitVal);
}
catch (Throwable t){
}
Where args[0] is the external process and c is the input (String) I need to feed to the process. If it was running correctly, I would get an exitVal=0, instead I get nothing. Also, what I really want to print is the output of the external process (which would be "6" in the given example).
You must use getInputStream() and getOutputStream() on the process to communicate it, see the javadocs.
If you do not read all data from the process, it might hang and even deadlock. For a short introduction on common problems, see this blog post. At the very least, you should be reading all data from the process output.
You cannot "get nothing". Method exitValue() returns primitive type, therefore it even cannot be null. But this method can stuck however. This happens because your process is still running.
Is is possible that it is running because you did not "feed" it? In this case the only thing you have to do is to call proc2.getOutputStream() and write what you need to this stream. If you want to read the process' output use proc2.getInputStream() and read from the stream.
BTW, take a look on ProcessBuilder. It provides better, more "object oriented" API thant simple Runtime.exec().
You can feed the program input with '<' redirection:
{
Process p = Runtime.getRuntime().exec("wc < pom.xml");
p.waitFor();
System.out.println(p.exitValue());
BufferedReader bri = new BufferedReader
(new InputStreamReader(p.getInputStream()));
String line;
while ((line = bri.readLine()) != null) {
System.out.println(line);
}
bri.close();
}
I'm launching wkhtmltopdf from within my Java app (part of a Tomcat server, running in debug mode within Eclipse Helios on Win7 64-bit): I'd like to wait for it to complete, then Do More Stuff.
String cmd[] = {"wkhtmltopdf", htmlPathIn, pdfPathOut};
Process proc = Runtime.getRuntime().exec( cmd, null );
proc.waitFor();
But waitFor() never returns. I can still see the process in the Windows Task Manager (with the command line I passed to exec(): looks fine). AND IT WORKS. wkhtmltopdf produces the PDF I'd expect, right where I'd expect it. I can open it, rename it, whatever, even while the process is still running (before I manually terminate it).
From the command line, everything is fine:
c:\wrk>wkhtmltopdf C:\Temp\foo.html c:\wrk\foo.pdf
Loading pages (1/6)
Counting pages (2/6)
Resolving links (4/6)
Loading headers and footers (5/6)
Printing pages (6/6)
Done
The process exits just fine, and life goes on.
So what is it about runtime.exec() that's causing wkhtmltopdf to never terminate?
I could grab proc.getInputStream() and look for "Done", but that's... vile. I want something that is more general.
I've calling exec() with and without a working directory. I've tried with and without an empty "env" array. No joy.
Why is my process hanging, and what can I do to fix it?
PS: I've tried this with a couple other command line apps, and they both exhibit the same behavior.
Further exec woes.
I'm trying to read standard out & error, without success. From the command line, I know there's supposed to be something remarkably like my command line experience, but when I read the input stream returned by proc.getInputStream(), I immediately get an EOL (-1, I'm using inputStream.read()).
I checked the JavaDoc for Process, and found this
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 [b]subprocess to block, and even deadlock[/b].
Emphasis added. So I tried that. The first 'read()' on the Standard Out inputStream blocked until I killed the process...
WITH WKHTMLTOPDF
With the generic command line ap & no params so it should "dump usage and terminate", it sucks out the appropriate std::out, then terminates.
Interesting!
JVM version issue? I'm using 1.6.0_23. The latest is... v24. I just checked the change log and don't see anything promising, but I'll try updating anyway.
Okay. Don't let the Input Streams fill or they'll block. Check. .close() can also prevent this, but isn't terribly bright.
That works in general (including the generic command line apps I've tested).
In specific however, it falls down. It appears that wkhtmltopdf is using some terminal manipulation/cursor stuff to do an ASCII-graphic progress bar. I believe this is causing the inputStream to immediately return EOF rather than giving me the correct values.
Any ideas? Hardly a deal-breaker, but it would definitely be Nice To Have.
I had the same exact issue as you and I solved it. Here are my findings:
For some reason, the output from wkhtmltopdf goes to STDERR of the process and NOT STDOUT. I have verified this by calling wkhtmltopdf from Java as well as perl
So, for example in java, you would have to do:
//ProcessBuilder is the recommended way of creating processes since Java 1.5
//Runtime.getRuntime().exec() is deprecated. Do not use.
ProcessBuilder pb = new ProcessBuilder("wkhtmltopdf.exe", htmlFilePath, pdfFilePath);
Process process = pb.start();
BufferedReader errStreamReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
//not "process.getInputStream()"
String line = errStreamReader.readLine();
while(line != null)
{
System.out.println(line); //or whatever else
line = reader.readLine();
}
On a side note, if you spawn a process from java, you MUST read from the stdout and stderr streams (even if you do nothing with it) because otherwise the stream buffer will fill and the process will hang and never return.
To futureproof your code, just in case the devs of wkhtmltopdf decide to write to stdout, you can redirect stderr of the child process to stdout and read only one stream like this:
ProcessBuilder pb = new ProcessBuilder("wkhtmltopdf.exe", htmlFilePath, pdfFilePath);
pb.redirectErrorStream(true);
Process process = pb.start();
BufferedReader inStreamReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
Actually, I do this in all the cases where I have to spawn an external process from java. That way I don't have to read two streams.
You should also read the streams of the spawned process in different threads if you dont want your main thread to block, since reading from streams is blocking.
Hope this helps.
UPDATE: I raised this issue in the project page and was replied that this is by design because wkhtmltopdf supports giving the actual pdf output in STDOUT. Please see the link for more details and java code.
A process has 3 streams: input, output and error. you can read both output and error stream at the same time using separate processes. see this question and its accepted answer and also this one for example.
You should read from the streams in a different thread.
final Semaphore semaphore = new Semaphore(numOfThreads);
final String whktmlExe = tmpwhktmlExePath;
int doccount = 0;
try{
File fileObject = new File(inputDir);
for(final File f : fileObject.listFiles()) {
if(f.getAbsolutePath().endsWith(".html")) {
doccount ++;
if(doccount >500 ) {
LOG.info(" done with conversion of 1000 docs exiting ");
break;
}
System.out.println(" inside for before "+semaphore.availablePermits());
semaphore.acquire();
System.out.println(" inside for after "+semaphore.availablePermits() + " ---" +f.getName());
new java.lang.Thread() {
public void run() {
try {
String F_ = f.getName().replaceAll(".html", ".pdf") ;
ProcessBuilder pb = new ProcessBuilder(whktmlExe , f.getAbsolutePath(), outPutDir + F_ .replaceAll(" ", "_") );//"wkhtmltopdf.exe", htmlFilePath, pdfFilePath);
pb.redirectErrorStream(true);
Process process = pb.start();
BufferedReader errStreamReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = errStreamReader.readLine();
while(line != null)
{
System.err.println(line); //or whatever else
line = errStreamReader.readLine();
}
System.out.println("after completion for ");
} catch (Exception e) {
e.printStackTrace();
}finally {
System.out.println(" in finally releasing ");
semaphore.release();
}
}
}.start();
}
}
}catch (Exception ex) {
LOG.error(" *** Error in pdf generation *** ", ex);
}
while (semaphore.availablePermits() < numOfThreads) {//till all threads finish
LOG.info( " Waiting for all threads to exit "+ semaphore.availablePermits() + " --- " +( numOfThreads - semaphore.availablePermits()));
java.lang.Thread.sleep(10000);
}
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).