命令行终端执行流程并从此流程输入交互

时间:2016-05-14 00:35:58

标签: java process

基本上,我在我的java应用程序上按下按钮时会运行一个进程。 并且该过程向OS的终端执行命令。 但有时这个命令需要与用户进行交互。 我想知道在需要时是否可以从流程到用户进行交互?

我的代码:

File marsSimulator = new File("resources/mars_simulator/Mars4_5.jar");
if(marsSimulator.exists() && temp.exists()){
   String res="";
   try {
     Process p = Runtime.getRuntime().exec(new String[]{"java","-jar",marsSimulator.getAbsolutePath(),tempAssembly.getAbsolutePath()});
     p.waitFor();

     InputStream is = p.getInputStream();

     byte b[] = new byte[is.available()];
     is.read(b, 0, b.length); // probably try b.length-1 or -2 to remove "new-line(s)"

     res = new String(b);

   } catch (Exception ex) {
     ex.printStackTrace();
   }
}

另外,我忘了说应用程序是用SWING制作的,并且进程的输出显示在TextArea上......我应该改变什么吗?

请注意,当与用户进行交互时,进程会阻止。如果没有,则该过程不会阻止!

在这种情况下我需要做什么(我不知道该怎么做)?

  1. 当流程需要互动时。我需要知道这个过程何时需要进行一些互动。
  2. 我需要以交互方式(逐行)获取流程生成的输出。
  3. P.S。:对于想要理解生产线的人,我使用的是火星模拟器(http://courses.missouristate.edu/KenVollmar/MARS/),我将jar应用程序发送到一个与mips汇编代码相关联的过程中。

    下一段代码正在使用我的项目

    希望它对下一位冒险者有所帮助!

    感谢Nicolas Filotto帮助我。

    我的班级ObservableStream:

    class ObservableStream extends Observable {
      private final Queue<String> lines = new ConcurrentLinkedQueue<>();
    
      public void addLine(String line) {
        lines.add(line);
        setChanged();
        notifyObservers();
      }
    
      public String nextLine() {
        return lines.poll();
      }
    
      public String getLine(){return lines.peek();}
    }
    

    代码的另一部分:

    Process p = Runtime.getRuntime().exec(new String[]{"java","-jar",marsSimulator.getAbsolutePath(),tempAssembly.getAbsolutePath()});
    
    //This code does the interaction from the process with the GUI ! Implied, input interaction+output interaction from the process
    ObservableStream out = new ObservableStream();
    // Observer that simply sends to my external process line by line what we put in
    // the variable output
    PrintWriter writer = new PrintWriter(p.getOutputStream(), true);
    out.addObserver(
      (o, arg) -> {
        ObservableStream stream = (ObservableStream) o;
        String line;
        while ((line = stream.nextLine()) != null) {
          writer.println(line);
        }
      }
    );
    
    ObservableStream input = new ObservableStream();
    input.addObserver(
      (o, arg) -> {
        ObservableStream stream = (ObservableStream) o;
        String line;
        while ((line = stream.nextLine()) != null) {
          outputTextArea.appendText(line+"\n");
        }
      }
    );
    
    // The thread that reads the standard output stream of the external process
    // and put the lines into my variable input
    new Thread(
      () -> {
        try (BufferedReader reader = new BufferedReader(
          new InputStreamReader(p.getInputStream()))
        ) {
           String line;
           while ((line = reader.readLine()) != null) {
             input.addLine(line);
          }
        } catch (IOException e1) {
          e1.printStackTrace();
      }
     }
    ).start();
    
    
    new Thread(
      ()->{
        while(p.isAlive()){
          String res = input.getLine();
          if(res!=null && res.equals("Enter integer value:")) {
            boolean integerIsRequested=true;
            Thread t=null;
            while(integerIsRequested){
              if(t==null) {
                t = new Thread(new Runnable() {
                  public void run() {
                    String test1 = JOptionPane.showInputDialog("Enter Integer value:");
                    while(!test1.matches("^\\d+$")){
                      test1 = JOptionPane.showInputDialog("Error: Not a valid Integer.\nEnter a correct Integer value:");
                    }
                    Integer i = Integer.valueOf(test1);
    
                    if (i != null) {
                      out.addLine(test1);
                    }
                  }
                });
                t.start();
    
              }
              if(!t.isAlive()){
                integerIsRequested=false;
              }
            }
          }
        }
        outputTextArea.appendText("Program executed\n");
      }
    ).start();
    

    顺便说一下,这篇文章是独一无二的Jarrod;)

4 个答案:

答案 0 :(得分:5)

要实现我个人使用的这种用例:

  1. Observable对象,用于在外部流程提供新行时通知我的用户界面
  2. 我添加了由我的UI提供的新行的Observable对象
  3. #{1}}#1将刷新我的UI数据
  4. #2的Observer将我的UI提供的行发送到我的外部流程
  5. 一个Observer将检查我的外部流程是否提供了新行,如果是,则会将这些行提供给#1
  6. 因为我没有完整的环境,我会告诉你如何使用模拟对象:

    首先我的虚假外部应用程序只收到他收到的Thread

    Echo

    如果此课程收到public class Echo { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while (true) { String line = scanner.nextLine(); System.out.printf("echo > %s%n", line); } } } ,则会打印到标准输出流foo

    然后我的echo > foo

    Observable

    NB:班级public class ObservableStream extends Observable { private final Queue<String> lines = new ConcurrentLinkedQueue<>(); public void addLine(String line) { lines.add(line); setChanged(); notifyObservers(); } public String nextLine() { return lines.poll(); } } (目前已实施)只能根据您的需要只有一个ObservableStream。实际上,它仅用于将UI与数据的检索或发布方式分离

    然后最后是主要代码:

    Observer

    如果此代码收到Process p = Runtime.getRuntime().exec( new String[]{"java", "-cp", "/my/path/to/my/classes", "Echo"} ); // The Observable object allowing to get the input lines from my external process ObservableStream input = new ObservableStream(); // A mock observer that simply prints the lines provided by the external process // but in your case you will update your text area instead input.addObserver( (o, arg) -> { ObservableStream stream = (ObservableStream) o; String line; while ((line = stream.nextLine()) != null) { System.out.printf("Line Received from the external process: %s%n", line); } } ); // The thread that reads the standard output stream of the external process // and put the lines into my variable input new Thread( () -> { try (BufferedReader reader = new BufferedReader( new InputStreamReader(p.getInputStream())) ) { String line; while ((line = reader.readLine()) != null) { input.addLine(line); } } catch (IOException e) { e.printStackTrace(); } } ).start(); // The Observable object allowing to send the input lines to my external process ObservableStream output = new ObservableStream(); // Observer that simply sends to my external process line by line what we put in // the variable output PrintWriter writer = new PrintWriter(p.getOutputStream(), true); output.addObserver( (o, arg) -> { ObservableStream stream = (ObservableStream) o; String line; while ((line = stream.nextLine()) != null) { writer.println(line); } } ); // A simple scanner used to send new messages to my external process Scanner scanner = new Scanner(System.in); while (true) { output.addLine(scanner.nextLine()); } ,则会打印到标准输出流foo

答案 1 :(得分:2)

我希望它能回答你的问题...... subProcessStuff“模仿”那个子流程。它可以是任何东西 - 但这样我们就拥有了一切。它需要2个参数传递到控制台。字符串和整数。 Gobbler获得了Callback这是一个接口,具有匿名实现 - 并且有对params的检查。要回答子进程是否等待,我们只需跟踪所说的内容 - 就像用户使用它一样。

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Scanner;

class Test1 {
    public static void main(String[] args) {
        for (String arg : args)
            System.out.println("arg: " + arg);

        for (String arg : args)
            if (arg.equals("-test")) {
                subProcessStuff();
                return;
            }
        mainProcess();

    }

    public static void subProcessStuff() {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        try {
            System.out.println("Enter String");
            String s = br.readLine();
            System.out.println("Enered String: " + s);
            System.out.println("Enter Integer:");
            int i = Integer.parseInt(br.readLine());
            System.out.println("Entered Integer: " + i);
        } catch (IOException e) {
            System.err.println("io error - " + e.getMessage());
        } catch (NumberFormatException nfe) {
            System.err.println("Invalid Format!");
        }
    }

    private static PrintStream out;

    public static void mainProcess() {
        String[] commands = { "ls", "-alt" };
        ProcessBuilder builder = new ProcessBuilder("java", "Test1", "-test");

        // builder.inheritIO(); // I avoid this. It was messing me up.

        try {
            Process proc = builder.start();
            InputStream errStream = proc.getErrorStream();
            InputStream inStream = proc.getInputStream();
            OutputStream outStream = proc.getOutputStream();

            new Thread(new StreamGobbler("err", out, errStream)).start();

            out = new PrintStream(new BufferedOutputStream(outStream));

            Callback cb = new Callback() {
                @Override
                public void onNextLine(String line) {
                    if (line.equals("Enter String")) {
                        out.println("aaaaa");
                        out.flush();
                    }
                    if (line.equals("Enter Integer:")) {
                        out.println("123");
                        out.flush();                    
                    }
                }
            };
            new Thread(new StreamGobbler("in", out, inStream, cb)).start();
            int errorCode = proc.waitFor();
            System.out.println("error code: " + errorCode);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }
}

interface Callback {
    void onNextLine(String line);
}

class StreamGobbler implements Runnable {
    private PrintStream out;
    private Scanner inScanner;
    private String name;
    private Callback cb;

    public StreamGobbler(String name, PrintStream out, InputStream inStream) {
        this.name = name;
        this.out = out;
        inScanner = new Scanner(new BufferedInputStream(inStream));
    }

    public StreamGobbler(String name, PrintStream out, InputStream inStream, Callback cb) {
        this.name = name;
        this.out = out;
        inScanner = new Scanner(new BufferedInputStream(inStream));
        this.cb = cb;
    }

    @Override
    public void run() {
        while (inScanner.hasNextLine()) {
            String line = inScanner.nextLine();
            if (cb != null)
                cb.onNextLine(line);
            System.out.printf("%s: %s%n", name, line);
        }
    }
}

答案 2 :(得分:1)

我认为你不能从Java检查进程的状态。但是,您可以使用某些Linux命令来执行此操作。 (当然,如果您使用的是Linux)

如果您的Java进程可以访问/proc目录,那么您可以阅读该进程的status文件。

例如,对于流程ID为12280

的流程
/proc/12280/status

以下是status文件的相关输出

Name:   java
State:  S (sleeping)
Tgid:   12280
Pid:    12280
PPid:   12279
...

第二行给出了该过程的状态。您需要运行一个线程来连续轮询此文件以读取状态。

答案 3 :(得分:0)

逐行代码我用来交互一个不同的jar,这是一个speechRecognizer。我想你想要实现这样的目标。

示例:

我正在进行交互的jar(speechRecognizer)执行不同的命令并运行其他一些Threads.Every时间它必须与主jar交互,它打印出我需要的东西。例如(用户说:你好吗),所以你可以拥有相同的逻辑,当外部jar需要与用户交互时,它会打印出一些内容并将其读入主app.So:

// About Process
private Process process;
private BufferedReader bufferedReader;
private boolean stopped = true;
Thread processChecker;

//Running it in a Thread so the app don't lags
new Thread(() -> {
        try {
            stopped = false;
            //Starting the external jar..
            ProcessBuilder builder = new ProcessBuilder("java", "-jar", System.getProperty("user.home")
                    + File.separator + "Desktop" + File.separator + "speechRecognizer.jar", "BITCH_PLEASE");
            //Redirecting the ErrorStream
            builder.redirectErrorStream(true);
            process = builder.start();
            bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;



            //Check continusly if the process is still alive
            //i case of crash i should do something..
            processChecker = new Thread(() -> {
                while (process.isAlive()) {
                    try {
                        Thread.sleep(1200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                stopSpeechReader(false);
            });
            processChecker.start();

            // Continuesly Read Output of external process
            while (!stopped) {
                while ((line = bufferedReader.readLine()) != null && !line.isEmpty()) {
                    System.out.println(line);
                    checkSpeechResult(line);
                }
            }

            // Interrupt the mf Thread if is Alive
            if (processChecker.isAlive())
                processChecker.interrupt();
            System.out.println("SpeechReader Stopped! Process is alive:" + process.isAlive() + " >Exit Value:"
                    + process.exitValue());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }).start();