有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

如何在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)
        {}
    }
}

这是由Jhon.java文件执行的Add.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);
        }
    }
}

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


共 (1) 个答案

  1. # 1 楼答案

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

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

    3. 与此同时,{}的线程仍在等待输入。如果你在你的平台上输入任何输入信号的结尾(在Unix上通常是control-D,但可以配置为其他东西,在Windows上是control-Z),它会将其视为EOF,readLine将返回null,因此s.getBytes()将抛出一个NullPointerException,你的catch(IOException){}将自动丢弃它,它将在没有实际发生的众多问题迹象的情况下退出

    寓意:除了一开始就试图编写正确的代码外,要意识到人类并不是每次都能做到完美,所以不要丢弃异常,除非你知道是什么导致了异常,并且在你的学习阶段你不知道。并且尽量不要丢弃其他错误信息(在本例中是来自子流程的错误流)

    修复:

    • 只调用getOutputStream一次,对于每个输入行(如果保持循环,则在循环中,但请参见下一步),执行os.write(line)os.flush(),但不执行os.close()

    • 或者按照@MadProgrammer的评论重新安排这个同步,或者重新安排,以便输入和发送线程t1在子进程退出时终止,或者等效地在接收和显示线程t2终止时终止,因为子进程退出br.readLine()==null指示EOF时终止,与class A不同,哪个class B测试正确。这很难自动完成,因为A已经位于readLine中,无法中断,至少不可靠。一种简单的方法是输出一条消息,告诉用户现在输入输入信号的末尾,然后编码A以正确处理EOF

    • 或者,一个真正的麻烦,但为了完整性,将t1作为守护进程线程,而不是join它。然后main将返回,一旦子进程退出并且t2终止,它将终止主线程,JVM将在不等待t1的情况下退出。因为这通常是一个坏主意,我不会给你“teh codez”,但谷歌搜索一下就会发现如何做到这一点