1
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..

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
James Cotter
  • 798
  • 11
  • 22
  • There is no way to "wait for it to finish and then read all the output". Read the JavaDoc for the Process class. It states: "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, and even deadlock." And it's not lying. The spawned process will block when it can't output any more data because you are not reading it out of the other end of the pipe. – brettw Feb 16 '12 at 06:45
  • I'd recommend this answer to similar question: http://stackoverflow.com/a/11336257/190335 – Tomato Jan 22 '14 at 06:42

3 Answers3

1

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.

Community
  • 1
  • 1
Adam Rofer
  • 6,121
  • 1
  • 14
  • 11
  • From the `p2.getInputStream()` Stream - sounds counter-intuitive but you're getting an **input** *from* the cmd call, and an **output** is sent *to* the cmd call. – Adam Rofer Feb 16 '12 at 05:22
  • No matter what I tried, I could not read anything using that code. – James Cotter Feb 16 '12 at 16:23
  • Here's some more information that might help shed some light: http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html – Adam Rofer Feb 16 '12 at 16:29
1

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;
    }
}

}

James Cotter
  • 798
  • 11
  • 22
0

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.

Jim Garrison
  • 85,615
  • 20
  • 155
  • 190