String cmd=" D:/James/1 ASU/REU/senna-v3.0/senna/senna-win32.exe -posvbs < \"D:/James/1 ASU/REU/senna-v3.0/senna/tmp.tmp\"";
Process p2 = Runtime.getRuntime().exec(cmd);
I want to run an application and push input into it from a text file. I tried the above and the application ran, but the application complained and says "<" is not a valid command line argument.
invalid argument: < D:/James/1 ASU/REU/senna-v3.0/senna/tmp.tmp
SENNA Tagger (POS - CHK - NER - SRL) (c) Ronan Collobert 2009
How the heck do I redirect input from a file? I need to read the output stream from the application as well, which I have done with:
p2.waitFor();
char[] cbuf = new char[1024];
BufferedReader processOutput = new BufferedReader(new InputStreamReader(p2.getInputStream()));
processOutput.read(cbuf);
processOutput.read(cbuf);
System.out.println(new String(cbuf));
I do not want to run the program and send text input from stdin. I just want to run the program once, wait for it to finish and then read all of the output. The main reason for this is because the application may take an indeterminate amount of time to finish and I don't want to deal with the issue that reading will block if there is no output, etc..
From Can Java Runtime.exec another java program that uses stdin? and this post:
Call the method Process.getOutputStream
and feed your input to the returned output stream.
...so this would look like:
String cmd = "D:/James/1 ASU/REU/senna-v3.0/senna/senna-win32.exe -posvbs";
Process p2 = Runtime.getRuntime().exec(cmd);
String fileInput = "D:/James/1 ASU/REU/senna-v3.0/senna/tmp.tmp";
BufferedWriter bufferedwriter = new BufferedWriter(new OutputStreamWriter(p2.getOutputStream()));
BufferedReader br = new BufferedReader(new FileReader(fileInput));
String s = br.readLine();
while (s != null)
{
bufferedwriter.write(s);
s = br.readLine();
}
bufferedwriter.flush();
...and you'd want to surround that with a try
/catch
and probably assign FileReader
to a variable to close()
it properly in a finally
block.
Interacting with a separate process in Java, done correctly involves starting two or three threads, one for each of stdin, stdout and stderr (if needed), and handling the I/O on the thread. Trying to do all of it on the main thread can result in your main thread or the external process hanging. For example, if you read the process's stdout first, and it requires input, everything will stall. If you handle sending the input first, and the output fills up the internal buffer, the external process will stall.
Launch a separate thread for each stream and do all the I/O on the thread. Join the main thread with the I/O threads and the external process to clean up after everything's done.
Why Java does not provide a library that does this is beyond me. Thanks to Jim for identifying that I need threads to read as java likes to make everything blocking lol...
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package sennaparser;
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author james
*/
public class SennaReader {
public String pathToSenna = "";
public String[] getReadOut(String input) throws IOException, InterruptedException
{
Runtime rt = Runtime.getRuntime();
String s = "cmd /C senna-win32.exe < tmp.tmp";
//s = "cmd /C dir";
FileWriter writer = new FileWriter( pathToSenna + "/tmp.tmp");
writer.write(input);
writer.close();
Process p;
String[] params = new String[1];
params[0] = "";
File f = new File(pathToSenna);
p = rt.exec(s, params, f);
BufferedReader processOutput = new BufferedReader(new InputStreamReader(p.getInputStream()), 500000);
BufferedWriter processInput = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
ReadThread r = new ReadThread(processOutput);
Thread th = new Thread(r);
th.start();
p.waitFor();
r.stop();
s = r.res;
p.destroy();
th.join();
return s.split("\n");
}
public class ReadThread implements Runnable{
BufferedReader reader;
char[] buf = new char[100000];
String res = "";
boolean stop;
public ReadThread(BufferedReader reader)
{
this.reader = reader;
stop = false;
}
@Override
public void run() {
res = "";
while (!stop) {
try {
reader.read(buf);
res += new String(buf);
} catch (IOException ex) {
Logger.getLogger(SennaReader.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public void stop()
{
stop = true;
}
}
}