如何读取输出并为java中的子进程提供输入

时间:2015-12-25 06:37:29

标签: java

我想制作一个Java程序来运行另一个Java程序。我写了一些代码来运行另一个Java程序。 Jhon.java是一个Java文件,我从中执行Add。类文件。但是在读取输出并向子进程提供输入时存在问题。我有这个代码。

import java.io.*;

class Jhon
{
    public static void main(String args[])
    {
        try
        {
            String command="java Add";
            Process proc=Runtime.getRuntime().exec(command);
            Thread t1=new A(proc);
            t1.start();
            Thread t2=new B(proc);
            t2.start();
            proc.waitFor();
            t1.join();
            t2.join();
       }
       catch(Exception e)
       {}
    }
}
class A extends Thread
{
    Process proc;
    A(Process proc)
    {
        this.proc=proc;
    }
    public void run()
    {
        BufferedReader br = new BufferedReader(new       InputStreamReader(System.in));
        try
        {
            while(true)
            {   
                String s = br.readLine();
                OutputStream out = proc.getOutputStream();
                out.write(s.getBytes());
                out.close();
            }
        }
        catch(Exception e)
        {}
    } 
}
class B extends Thread
{
    Process proc;
    B(Process proc)
    {
        this.proc=proc;
    }
    public void run()
    {
        try
       {
            String line="";
            BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            while((line=br.readLine())!=null)
            {
                System.out.println(line);
            }
        }
        catch(Exception e)
        {}
    }
}

这是由Add.java文件

执行的Jhon.java文件
import java.io.*;

class Add
{
    public static void main(String args[])
    {
        int a,b,c;
        try
        {
            BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
            System.out.println("Enter first number");
            a=Integer.parseInt(br.readLine());
            System.out.println("Enter second number");
            b=Integer.parseInt(br.readLine());
            c=a+b;
            System.out.println("Addition is "+c);
        }
        catch(IOException e)
        {
            System.out.println(e);
        }
    }
}

当我从Add.java文件执行Jhon.java文件时,它要求输入第一个数字。提供第一个号码后,它要求输入第二个号码。提供第二个数字后,它不会打印添加。终端挂了。那么我做错了什么?请给我一个解决方案。

1 个答案:

答案 0 :(得分:0)

  1. 您的class A读取第一行输入,调用getOutputStream()os.write()以(开始)将该行发送到子流程,然后调用os.close() 。刷新数据后,将关闭与子进程的标准输入进行通信的管道。然后它循环读取下一行并再次尝试getOutputStreamwriteclose,但写入什么都不做,因为它被缓冲并且关闭实际上因为管道关闭而失败但它抑制了内部异常,我相信autoclose是安全的。然后它等待进一步的输入。

  2. 子进程中的class Add成功读取第一行;当它试图读取第二行时,它的标准输入(来自主机的管道)已正常关闭,这被认为是“EOF”(文件结束)。 br.readLine()返回null以表示EOF,但是您将其传递给Integer.parseInt,这会导致NullPointerException,但不会被捕获(它不是IOException的子类型所以Java默认是在标准错误上显示堆栈跟踪并退出。子进程的标准错误作为单独的流(而不是“输入”流)传送给主进程,并且主服务器没有查看它,因此信息丢失。

  3. 同时(线程)您的class A仍在等待输入。如果您在平台上输入任何输入结束信号(通常是Unix上的控制-D,但可以配置为其他内容,在Windows上为control-Z),则会将其视为EOF,readLine将返回null所以s.getBytes()会抛出NullPointerExceptioncatch(IOException){}将默默地丢弃,并且它将退出,但不会显示实际发生的众多问题。

  4. 道德:除了首先尝试编写正确的代码之外,要意识到人类每次都不会完美无缺,所以除非你知道某些什么,否则不要抛弃异常引起了他们 - 在你学习的阶段你不知道。并且尽量不要丢弃其他错误信息(在这种情况下是来自子进程的错误流)。

    修正:

    • 只调用getOutputStream一次,并且对于每个输入行(如果你保持循环但在循环中看到下一个),请os.write(line)os.flush()但不是{{1 }}

    • 要么在@MadProgrammer注释时将其重新排列为同步,要么排列,以便在子进程退出时终止输入和发送线程os.close(),或等效于接收和显示线程时t1终止 - 当t2指示EOF时它会执行,因为子进程已退出,br.readLine()==null正确测试,与class B不同。这很难自动执行,因为class A已经位于A中,不能被中断,至少不可靠。一种简单的可能性是输出一条消息,告诉用户现在输入输入结束信号,并编码readLine以正确处理EOF。

    • 或者,真正的kludge,但为了完整性,让A成为守护程序线程而 t1它。然后join将返回,一旦子进程退出并且main已终止,终止主线程,JVM将退出而不等待t2。因为这通常是一个坏主意,我不会给你'teh codez',但有点谷歌搜索会发现如何做到这一点。