Sending output to external process - java

For some reason, I'm having problems sending output to a process that I've created in Java. The external process is running in a command prompt, and the peculiar thing is that I can click that, type, hit enter, and I'll get output from the program. It addition my program can read all the output coming from the program, it just can't send anything to it.
Anyways, here is the relevant code I'm using that just isn't working...
try {
ProcessBuilder builder=new ProcessBuilder(args);
builder.redirectErrorStream(true);
final Process p=builder.start();
// Process has been created and is running
try {
String b="";
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
final BufferedWriter output = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
new Thread(){public void run(){
// This thread will periodically send "get_time" to the process to get an update on its progress
while(true)
{
try {
Thread.sleep(1000);
p.exitValue();
// p.exitValue() only works when process has ended, so normal code goes in the catch block
output.close();
break;
// Leave the infinite loop if the program has closed
} catch (IOException ex) {
Logger.getLogger(OvMusicUI.class.getName()).log(Level.SEVERE, null, ex);
break;
// Leave the infinite loop if we tried closing our output stream, but it was already closed
} catch (InterruptedException ex) {
Logger.getLogger(OvMusicUI.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalThreadStateException e) {
try {
System.out.println("Outputted: get_time");
output.write("get_time" + System.lineSeparator());
output.flush();
// Give the process some input
} catch (IOException ex) {
Logger.getLogger(OvMusicUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}}.start();
while((b = input.readLine()) != null){
System.out.println(new Time(System.currentTimeMillis()).toString() + " " + b);
// Log all output the process gives
}
input.close();
} catch (IOException ex) {
Logger.getLogger(OvMusicUI.class.getName()).log(Level.SEVERE, null, ex);
}
// More code here
} catch (IOException ex) {
Logger.getLogger(OvMusicUI.class.getName()).log(Level.SEVERE, null, ex);
}
If necessary, I can give an example command and the name of the external program being run so you can try it yourself...
Thanks!
EDIT: Here is an example of what's passed into the ProcessBuilder: Arrays.asList("VLC\vlc.exe", "-Irc", "-vvv", "http://www.youtube.com/watch?v=xfeys7Jfnx8", "--sout", "file/ogg:Untitled 1.ogg", "--play-and-exit", "--rc-quiet"). The only difference is I use absolute paths instead of relative paths. The program is VLC Media Player 2.0.7.

Your code has a few problems. First, you generally should not use exceptions for your regular control flow: it's expensive, it's difficult to read, and it makes handling actual errors more difficult. It's generally better to spawn another Thread that calls p.waitFor() and signals your main thread to complete, such as with wait/notify.
Also, your construction with the infinite loop and using break instead of return will make your code more difficult to debug; instead, use a Timer.
It looks like the output to your external program probably is working correctly but that the problem is just with reading its output. The program may be buffering its own output or may be detecting that it's not being run interactively and behaving differently.

Related

VM Terminated on static method

public static void main() {
String fileName = "cardNumbers.txt";
String line = null;
try {
FileReader fileReader = new FileReader(fileName);
BufferedReader bufferedReader = new BufferedReader(fileReader);
while((line = bufferedReader.readLine()) != null)
{
CreditCard card = new CreditCard(line);
if (card.creditCardType().equalsIgnoreCase("Unknown"))
{
System.out.println("Card number " + card.getCardNumber() + "is an unknown credit card type.");
}
else if (card.isValid())
{
System.out.println(card.creditCardType() + " number" + card.getCardNumber() + " is valid.");
}
else if (!card.isValid())
{
System.out.println(card.creditCardType() + " number " + card.getCardNumber() + " is not valid.");
}
}
}
catch (FileNotFoundException ex)
{
System.out.println("file not found exception thrown");
}
catch (IOException ex)
{
System.out.println("error while reading the file");
}
finally
{
System.exit(0);
}
}
When I run this method it just says ProcessCardNumbers.main(); VM Terminated. Instead of actually printing out the content.
If I add a print at the very start of the function or in the finally block, they are printed.
Im not sure why this is happening or how I can fix it.
As you told us that:
Adding a println at the start is printed
and
Adding a println in the finally works too
we can deduce that your code is working. It's just that when you reach while((line = bufferedReader.readLine()) != null), line stays null, so you never enter your while.
Why is that? Well, your file may be empty to begin with. If it is not, double-check the encoding of your file: it may not be using the proper returns symbols, hence not having a "completed line".
This seems that in your text file cardNumbers.txt has no data. When this program will execute within while loop bufferedReader.readLine()). will return null. So loop will terminate. After termination you have written System.exit(0); function in finally block which terminate JVM on the spot. So JVM is terminated now that's why you are not able to see anything after working of this code.
If you want to check working, write one SOP statement in finally block. Probably that will execute without termination of JVM.
The problem here is not the bug in your code but the design problem that does not let you see the bug.
You are probably getting an undeclared exception (RuntimeException) and the VM can't print it because you kill it before in the finally.
You have several options:
Remove the System.exit(0); and let it die normally. This may fail if there is another non-daemon thread running. You may try to stop it. You can, for example, cancel a Timer.
Add a catch (RuntimeException e) { section before the finally and print the captured error. e.printStackTrace(); should do the trick.
With any of those you should see the exception on console so you can fix it.
Your main method signature must look like this:
public static void main(String[] args)
instead of
public static void main()

How can I wait for a subprocess to complete in a process in Java?

this is basically what I am trying to do: I created a Process that simulates the command line. Like this:
private Process getProcess() {
ProcessBuilder builder = new ProcessBuilder("C:/Windows/System32/cmd.exe");
Process p = null;
try {
p = builder.start();
} catch (IOException e1) {
e1.printStackTrace();
}
return p;
}
Now I can "feed" this process with commands:
BufferedWriter p_stdin = new BufferedWriter(
new OutputStreamWriter(process.getOutputStream()));
try {
p_stdin.write("dir"); // Just a sample command
p_stdin.newLine();
p_stdin.flush();
} catch (IOException e) {
e.printStackTrace();
return "Failed to run " + fileName;
}
What I now would like to do is wait for the command, that is the subprocess of my process, to complete. How can I do that? I know that I can wait for processes with the waitFor() method, but what about a subprocess??
The dir command is not a subprocess, it is executed internal to cmd. However, this is not much relevant, anyway: from the perspective of Java any other command, which is launched in a subprocess, would behave the same.
To wait for the dir command to complete you must interpret the incoming stdout output from cmd and realize when the prompt was printed again. This is a quite brittle mechanism, though.
In any case, you currently don't consume cmd's stdout at all, which will cause it to block soon, never recovering.

How to properly close file-to-string input stream? (IOUtils FileUtils)

I have two file-to-string processes in my app (one actually deals with an asset file).
If I repeat either of these processes a few times on the same file, I get OutOfMemoryErrors.
I suspect it might be because I'm not closing the streams properly and therefore maybe causing multiple streams to be created, and this is perhaps causing my app to run out of memory.
Here is the code of the two processes:
My asset-file-to-string process.
As you can see, I have have something in place to close the stream but I don't know if it's formatted properly.
try
{
myVeryLargeString = IOUtils.toString(getAssets().open(myAssetsFilePath), "UTF-8");
IOUtils.closeQuietly(getAssets().open(myAssetsFilePath));
}
catch (IOException e)
{
e.printStackTrace();
}
catch(OutOfMemoryError e)
{
Log.e(TAG, "Ran out of memory 01");
}
My file-to-string process.
I have no idea how to close this stream (if there is even a stream to close at all).
myFile01 = new File(myFilePath);
try
{
myVeryLargeString = FileUtils.readFileToString(myFile01, "UTF-8");
}
catch (IOException e)
{
e.printStackTrace();
}
catch(OutOfMemoryError e)
{
Log.e(TAG, "Ran out of memory 02");
}
It's difficult to say what may cause OOME but closing should be like this
InputStream is = getAssets().open(myAssetsFilePath);
try {
myVeryLargeString = IOUtils.toString(is, "UTF-8");
} finally {
IOUtils.closeQuietly(is);
}

Java BufferedReader, how to only call if will not block?

I have 2 sockets and I am using BufferedReader around it's InputStreams. What I am trying to do is take all input from the first socket and send it to the other socket (and visa versa).
The problem is that if the first one does not send a message, it will still block on the first readLine() even though the 2nd socket has already sent some data and is ready. I would like to continue with this simple approach of using no additional threads.
Here's some code that I wrote up, as you can see I have 2 BufferedReaders (in0 and in1) , the program gets stuck at in0.readLine() (blocking).
private void network()
{
PrintWriter out0 = null, out1 = null;
BufferedReader in0 = null,in1 = null;
try{
//clients[] is an array of Socket[2]
in0 = new BufferedReader(new InputStreamReader(clients[0].getInputStream()));
out0 = new PrintWriter(clients[0].getOutputStream(), true);
in1 = new BufferedReader(new InputStreamReader(clients[1].getInputStream()));
out1 = new PrintWriter(clients[1].getOutputStream(), true);
} catch (IOException e) {
System.out.println("Accept failed: 4445");
System.exit(-1);
}
int count = 1;
while(true)
{
System.out.println("network check loop # " + count);
++count;
String nextMessage = null;
try {
if( (nextMessage = in0.readLine()) != null)
{
this.relayMessage(nextMessage,out1);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Middle of network check loop");
nextMessage = null;
try {
if((nextMessage = in1.readLine()) != null)
{
this.relayMessage(nextMessage,out0);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
How can I just skip that statement if in0 is not ready to give me some data? I have seen BufferedReader's ready() method and have attempted to use in0.ready() && readLine() but this causes an infinite loop as neither of the bufferedreaders appear to ever be 'ready'. As well, I am certain that the messages being sent over the socket end in newline characters so readLine() should process correctly!
Any ideas?
Try to use setSoTimeout to put a timeout on your read(), then you just need to catch the SocketTimeoutException if the timer has expired.
Here break and continue keywords are your friends.
The simplest approach is to use two threads. This way you don't have to write your own scheduling code to determine which thread should be running. BTW: The code to copy from one socket to another is the same in each thread, reducing duplication.
To manage your threads I would use an ExecutorService which will make shutting downt eh threads easier.

Java proc.waitfor() is being ignored on mac

i ve written a simple program to run on a mac, the program opens an excel file and waits for the the user to close the file after which a simple output is given. when i run the program, excel opens, the proc.waitfor is ignored and it just skips to the output without waiting, any help
thanks
Thread myThread = new Thread() {
#Override
public void run() {
try {
String userDir = (System.getProperty("user.home"));
String fileName = userDir + "/Desktop/test/testfile.xlsx";
File theFile = new File(fileName);
Process proc = new ProcessBuilder("/usr/bin/open", fileName).start();
int waitFor = proc.waitFor();
} catch (InterruptedException ex) {
Logger.getLogger(MacTester.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(MacTester.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
myThread.start();
System.out.println("excel is now closed");
This line:
System.out.println("excel is now closed");
Should be inside the run method. Your main thread, the thread that is starting your other thread continues with the execution after start has been invoked.
Another alternative is to place:
myThread.join();
on the line after:
myThread.start();
/usr/bin/open doesn't run modally, it returns the control after launching the appropriate application. You should use open -W. Consider using open -W -n which opens the file in a new instance of the application. Consult man open and try in terminal before testing your java code.
You're doing your process (appropriately) in a background thread, and so what effect will waitfor have on the completely separate calling thread? Answer: none. The solution I see has been given in the other answer -- +1 to him. :)

Categories