5

I want to write a Java program that runs an external "java myprog < input.txt > output.txt" command. The eventual goal is to run this command on two different programs and compare their output similarity from their respective output files.

I think I've read just about every relevant article about using ProcessBuilder to run an external program, and the few entries about handling user input in that external program, but I still can't get things working. From what I have read, I think the best approach is to not run the exact command above, but instead read the input.txt file and feed it byte-by-byte into the Process object, then collect the output and write it to output.txt ... I am 100% open to other options.

I put together the code below based on my readings. It seems to correctly feed input from input.txt into myprog, but when I try to print the external program's output to the console to verify, the program hangs at the point where (surprise) user input is expected in myprog.

I get the same issues with and without the redirectErrorStream(true) line.

I really want this to be in Java since I plan to share the source code with the people whose program outputs I will compare, and they are primarily only familiar with Java.

import java.io.*;
import java.util.*;

public class test7 {

    public static void main(String args[]) {

        try {
            // WANT: "java myprog < input.txt > output.txt"
            String inputFile = "input.txt";
            String outputFile = "output.txt";

            ProcessBuilder pb = new ProcessBuilder("java","myprog");
            pb.redirectErrorStream(true); // merge stdout, stderr of process
            Process p = pb.start();

            // write input to the running program
            OutputStream pos = p.getOutputStream();
            InputStream fis = new FileInputStream(inputFile);
            int read = 0;
            while ( (read = fis.read()) != -1) {
                pos.write(read);
            }
            fis.close();

            // get output of running program
            InputStreamReader isr = new  InputStreamReader(p.getInputStream());
            BufferedReader br = new BufferedReader(isr);

            // HANGS HERE WHEN USER INPUT REQUIRED
            String lineRead;
            while ((lineRead = br.readLine()) != null) {
                System.out.println(lineRead);
            }

        }
        catch (IOException e) {
            e.printStackTrace(); 
        }
    } // end main

}

Here is the content of myprog.java:

import java.io.*;

public class myprog {

    public static void main(String args[]) throws IOException {

        System.out.println("Hello world!");
        System.out.println("Enter something:");

        BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));

        // the readLine() command causes ProcessBuilder to hang
        cin.readLine();
    }   
}

And the input.txt file is just

p

The output.txt file should be

Hello world!
Enter something:
missthang
  • 51
  • 3
  • What do you mean by user input required? Can you either show your myprog or at least its most pertinent parts? Also, please follow Java naming conventions if you want better help here. Your use of non-standard naming (including not capitalizing first letters of class names) makes your code confusing. – Hovercraft Full Of Eels Apr 18 '12 at 14:49
  • 2
    I answered this some time ago.. http://stackoverflow.com/questions/3062305/executing-shell-commands-from-java/3062874#3062874 – dsmith Apr 18 '12 at 14:51
  • @HovercraftFullOfEels: I added the content of myprog.java to the description. I apologize for not capitalizing the class name. – missthang Apr 18 '12 at 15:44
  • @dsmith: I copied and pasted your code with the commands "java myprog" and "java myprog < input.txt", but the program still hangs in the same way. – missthang Apr 18 '12 at 15:46
  • You may need to handle your standard streams concurrently. I would give Hovercraft the rep. – dsmith Apr 18 '12 at 22:44

3 Answers3

4

I wonder if your problem is partly to do with not using separate threads for reading input and writing output. For instance:

   public static void main(String args[]) {

      try {
         // WANT: "java myprog < input.txt > output.txt"
         String inputFile = "input.txt";
         String outputFile = "output.txt";

         // my ProcessBuilder Strings will be different from yours
         ProcessBuilder pb = new ProcessBuilder("java", "-cp", ".;bin;",
               "yr12.m04.a.MyProg");
         pb.redirectErrorStream(true); 
         Process p = pb.start();

         final OutputStream pos = p.getOutputStream();
         final PrintWriter pw = new PrintWriter(pos);
         final InputStream fis = new FileInputStream(inputFile);
         final BufferedReader fileBr = new BufferedReader(new InputStreamReader(fis));

         InputStreamReader isr = new InputStreamReader(p.getInputStream());
         final BufferedReader br = new BufferedReader(isr);

         new Thread(new Runnable() {
            public void run() {
               String lineRead;
               try {
                  while ((lineRead = br.readLine()) != null) {
                     System.out.println(lineRead);
                  }
               } catch (IOException e) {
                  e.printStackTrace();
               } finally {
                  if (br != null) {
                     try {
                        br.close();
                     } catch (IOException e) {
                        e.printStackTrace();
                     }
                  }
               }
            }
         }).start();

         new Thread(new Runnable() {
            public void run() {
               try {
                  String lineRead;
                  while ((lineRead = fileBr.readLine()) != null) {
                     pw.println(lineRead);
                  }
               } catch (IOException e) {
                  e.printStackTrace();
               } finally {
                  if (pw != null) {
                     pw.close();
                  }
                  if (fileBr != null) {
                     try {
                        fileBr.close();
                     } catch (IOException e) {
                        e.printStackTrace();
                     }
                  }
               }
            }
         }).start();

      } catch (IOException e) {
         e.printStackTrace();
      }
   } // end main
Hovercraft Full Of Eels
  • 276,051
  • 23
  • 238
  • 346
0

Have you thought about using Runtime.getRuntime().exec() instead?

Process proc = Runtime.getRuntime().exec("java myprog "+inputFile+" "+outputFile);
Speckpgh
  • 3,242
  • 1
  • 26
  • 42
0

You could include the jar of the 'myprog' and call the main() method yourself. Even more so if myprog is in your domain you could get rid of the main method altogether.

Angelo Fuchs
  • 9,254
  • 27
  • 66