如何在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 楼答案
你的
class A
读取第一行输入,调用getOutputStream()
和os.write()
将该行发送到子进程,然后调用os.close()
。刷新数据后,将关闭与子流程的标准输入进行通信的管道。然后,它循环读取下一行,并再次尝试getOutputStream
和write
和close
,但写操作什么也不做,因为它是缓冲的,而关闭实际上失败了,因为管道关闭了,但它抑制了内部异常,我相信这样自动关闭是安全的。然后等待进一步的输入子流程中的
class Add
成功读取第一行;当它试图读取第二行时,其标准输入(来自主控的管道)已正常关闭,这被视为“EOF”(文件结束)br.readLine()
返回null
以指示EOF,但您将其传递给Integer.parseInt
,这会导致NullPointerException
,但不会被捕获(它不是IOException
的子类型),因此Java默认为在标准错误上显示stacktrace并退出。子流程的标准错误作为一个单独的流(不是“输入”流)通过管道传输到主流程,而主流程没有查看它,因此信息会丢失与此同时,{}的线程仍在等待输入。如果你在你的平台上输入任何输入信号的结尾(在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”,但谷歌搜索一下就会发现如何做到这一点