Программа Java, которая запускает внешнюю программу java myprog ‹ input.txt › output.txt

Я хочу написать программу Java, которая запускает внешнюю команду «java myprog ‹ input.txt > output.txt». Конечная цель состоит в том, чтобы запустить эту команду в двух разных программах и сравнить сходство их выходных данных с соответствующими выходными файлами.

Я думаю, что прочитал почти все соответствующие статьи об использовании ProcessBuilder для запуска внешней программы и несколько статей об обработке пользовательского ввода в этой внешней программе, но я все еще не могу заставить все работать. Из того, что я прочитал, я думаю, что лучший подход - не запускать точную команду выше, а вместо этого читать файл input.txt и побайтно передавать его в объект Process, затем собирать вывод и записывать его в вывод .txt ... Я на 100% открыт для других вариантов.

Я собрал код ниже на основе моих чтений. Кажется, что входные данные из input.txt правильно подаются в myprog, но когда я пытаюсь распечатать вывод внешней программы на консоль для проверки, программа зависает в том месте, где (сюрприз) ожидается ввод данных пользователем в myprog.

Я получаю те же проблемы со строкой redirectErrorStream(true) и без нее.

Я действительно хочу, чтобы это было на Java, так как я планирую поделиться исходным кодом с людьми, чьи результаты программы я буду сравнивать, и они в основном знакомы только с 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

}

Вот содержимое 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();
    }   
}

И файл input.txt просто

p

Файл output.txt должен быть

Hello world!
Enter something:

person missthang    schedule 18.04.2012    source источник
comment
Что вы подразумеваете под требованием пользовательского ввода? Можете ли вы показать свою myprog или, по крайней мере, ее наиболее важные части? Кроме того, пожалуйста, следуйте соглашениям об именах Java, если вам нужна помощь. Использование вами нестандартного именования (включая отсутствие заглавных букв в именах классов) делает ваш код запутанным.   -  person Hovercraft Full Of Eels    schedule 18.04.2012
comment
Я ответил на это некоторое время назад. .com/questions/3062305/   -  person dsmith    schedule 18.04.2012
comment
@HovercraftFullOfEels: я добавил в описание содержимое myprog.java. Прошу прощения за то, что не написал название класса с большой буквы.   -  person missthang    schedule 18.04.2012
comment
@dsmith: я скопировал и вставил ваш код с помощью команд java myprog и java myprog ‹ input.txt, но программа все равно зависает.   -  person missthang    schedule 18.04.2012
comment
Возможно, вам потребуется одновременно обрабатывать стандартные потоки. Я бы дал Hovercraft репутацию.   -  person dsmith    schedule 19.04.2012


Ответы (3)


Интересно, ваша проблема частично связана с тем, что вы не используете отдельные потоки для чтения ввода и записи вывода. Например:

   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
person Hovercraft Full Of Eels    schedule 18.04.2012
comment
Вот и все! Отлично работает с переключателем пути к классам из команды java. Большое спасибо!!!!! - person missthang; 18.04.2012

Думали ли вы об использовании вместо этого Runtime.getRuntime().exec()?

Process proc = Runtime.getRuntime().exec("java myprog "+inputFile+" "+outputFile);
person Speckpgh    schedule 18.04.2012
comment
Это не имеет преимуществ перед использованием ProcessBuilder. - person Hovercraft Full Of Eels; 18.04.2012
comment
Я пропустил ‹ и › в моем примере, вы добавили их? @Hovercraft ... 1 строка кода против 10 всегда является преимуществом в моей книге, но каждому свое. - person Speckpgh; 18.04.2012
comment
Да, я добавил ‹ и › в свой тест. - person missthang; 18.04.2012
comment
@ user282172 - Я не думаю, что стандартные перенаправления ввода-вывода работают в объектах Java Process. По крайней мере, не на всех платформах. - person dsmith; 19.04.2012
comment
Затем просто напишите пакетную программу/оболочку-оболочку, которая вызывает программу java, и пусть ваш exec вызовет эту передачу в именах входных и выходных файлов. - person Speckpgh; 19.04.2012

Вы можете включить банку «myprog» и самостоятельно вызвать метод main(). Более того, если myprog находится в вашем домене, вы можете вообще избавиться от основного метода.

person Angelo Fuchs    schedule 18.04.2012