12.6 Java虚拟机读写其他进程的数据
一、回顾
回顾Java的Runtime类可以单独启动一个进程来运行操作系统的命令,如下程序所示:
package section6;
public class ExecTest
{
public static void main(String[] args)
throws Exception
{
//程序不能创建自己的Runtime实例,但是可以通过getRuntime()
//获取与之相关联的Runtime实例
var rt=Runtime.getRuntime();
//运行记事本
rt.exec("notepad.exe");
}
}
二、Runtime对象的exec()产生Process对象的
使用Runtime对象的exec()方法可以运行平台上的其他程序,该方法产生一个Process对象,Process对象代表由该Java程序启动子进程。Process对象提供了如下三个方法,用于让程序和其他子进程之间进行通信。
★InputStream getErrorStream():获取子进程的错误流。
★InputStream getInputStream():获取子进程的输入流。
★OutputStream getOutputStream():获取子进程的输出流。
注意:如果试图让子进程读取程序中的数据,那么应该使用输出流。要站在Java角度来看问题,子程序读取Java程序的数据,就是让Java程序把数据输出到子进程中(就像把数据输出到文件中一样,只是由子进程节点代替了文件节点),所以应该使用输出流。
2.1 获取子程序的输出流作为本程序的输入流
下程序示范了读取其他进程的输出信息:
package section6;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class ReadFromProcess
{
public static void main(String[] args)
throws Exception
{
//运行javac命令,返回该命令的子进程
Process p=Runtime.getRuntime().exec("javac");
try(
//以p进程的错误输出流创建BufferedRead对象
//这个错误流对p进程是输出流,对于本程序是输入流
//1、首先将这个错误流转换为字符流
var cs=new InputStreamReader(p.getInputStream());
//2、转换流转化为BufferedReader流
var br=new BufferedReader(cs)
)
{
String buff=null;
while((buff=br.readLine())!=null)
{
System.out.println(buff);
}
}
}
}
上面程序使用Runtime启动了javac程序,获取了运行该程序的子进程;然后以p进程的错误输入流创建了bufferedReader,这个输入流的流向如图所示:
注:以前版本的javac进程的错误输入流要通过getErrorStream()方法获取,现在改为getInputStream()方法获取。
下图所示的数据流对p进程(javac进程)而言,它是输出流;但对本程序而言,它是输入流——衡量输入输出流总是站在本程序所在的内存角度,所以数据流应该是输入流。
2.2 本程序的输出流作为子进程的输入流
可以通过Process的getOutputStream()方法获得项进程输入数据的流(该流对Java程序是输出流,对子进程则是输入流),下面程序实现了在Java程序中启动Javaxu
import java.io.*;
import java.util.*;
public class WriteToProcessplus
{
public static void main(String[] args)
throws IOException
{
// 运行java ReadStandard命令,返回运行该命令的子进程
Process p = Runtime.getRuntime().exec("java ReadStandardplus");
try (
// 以p进程的输出流创建PrintStream对象
// 这个输出流对本程序是输出流,对p进程则是输入流
var ps = new PrintStream(p.getOutputStream()))
{
// 向ReadStandard程序写入内容,这些内容将被ReadStandard读取
ps.println("普通字符串");
ps.println(new WriteToProcessplus());
}
}
}
// 定义一个ReadStandard类,该类可以接受标准输入,
// 并将标准输入写入out.txt文件。
class ReadStandardplus
{
public static void main(String[] args)
{
try (
// 使用System.in创建Scanner对象,用于获取标准输入
var sc = new Scanner(System.in);
var ps = new PrintStream(new FileOutputStream("out.txt")))
{
// 增加下面一行将只把回车作为分隔符
sc.useDelimiter("\n");
// 判断是否还有下一个输入项
while (sc.hasNext())
{
// 输出输入项
ps.println("键盘输入的内容是:" + sc.next());
}
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
}
在WriteToProcess中使用Runtime的exec()方法来运行java ReadStandard命令,该命令将运行ReadStandard类,并返回该程序的子进程。var ps = new PrintStream(p.getOutputStream())获取子进程的p的输出流——该输出流对于p进程是输入流,对于本程序是输出流。本程序通过该输出流向进程p中输入数据。
运行后将看到一个out.txt文档,内容为: