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:
5
  • 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. Commented Apr 18, 2012 at 14:49
  • 2
    I answered this some time ago.. stackoverflow.com/questions/3062305/… Commented Apr 18, 2012 at 14:51
  • @HovercraftFullOfEels: I added the content of myprog.java to the description. I apologize for not capitalizing the class name. Commented Apr 18, 2012 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. Commented Apr 18, 2012 at 15:46
  • You may need to handle your standard streams concurrently. I would give Hovercraft the rep. Commented Apr 18, 2012 at 22:44

3 Answers 3

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
Sign up to request clarification or add additional context in comments.

1 Comment

That's it! Works perfectly with the classpath switch from the java command. Thank you so much!!!!!
0

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

Process proc = Runtime.getRuntime().exec("java myprog "+inputFile+" "+outputFile);

5 Comments

This has no advantage over use of ProcessBuilder.
I left ou the "<" and ">" in my example, did you add these? @Hovercraft... 1 line of code vs 10 is always an advantage in my book, but to each their own.
Yes, I added the "<" and ">" in my test.
@user282172 - I don't think the standard io redirects work in Java Process objects. At least they wouldn't on all platforms.
Then simply write a wrapper batch/shell program that call the java program, and have your exec call this passing in the in and out file names.
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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.