1. 标准输入输出流:
1) 标准I/O流就是指System.in、System.out、System.err这三个,分表表示标准输入流、标准输出来、标准错误流;
2) 三者默认的流节点分别是键盘、屏幕、屏幕,这也是我们频繁使用的三个I/O流;
2. 标准流重定向:
1) 即人为改变三个标准流的流节点,比如吧System.out的流节点人为改成某个文件,那么在使用System.out输出的时候就不是输出到屏幕了而是输出到那个文件了;
2) 简单地说就是改变标准流原来默认的流向而已;
3) System提供了3个静态方法对标准流重定向:
i. static void setIn(InputStream in); // 重定向标准输入流
ii. static void setOut(PrintStream out); // 重定向标准输出流
iii. static void setErr(PrintStream err); // 重定向标准错误流
!!可以看到两个输出流必须要用处理流来重定向(当然必须要确定底层的流节点),而输入流一般用一个节点流来重定向就行了;
4) 示例:分别重定向输出流和输入流
public class Test {
public static void main(String[] args) throws IOException {
try (PrintStream ps = new PrintStream(new FileOutputStream("out.txt"))) {
PrintStream old = new PrintStream(System.out); // 备份
System.setOut(ps);
System.out.println("lalala");
System.out.println(new Test());
System.setOut(old); // 还原
}
try (FileInputStream fis = new FileInputStream("src\\com\\lirx\\Test.java")) {
System.setIn(fis);
Scanner sc = new Scanner(System.in);
sc.useDelimiter("\n");
while (sc.hasNext()) {
System.out.println(sc.next());
}
}
}
}
3. JVM读写其它进程的数据:
1) 我们知道可以通过Runtime.getRuntime().exec(String cmd)在当前进程中执行平台上的另一个子进程,该方法返回代表该子进程句柄的Process对象;
2) 现在我们要做的就是父子两个进程之间进行通信(数据交流);
3) Process对象提供了三个方法来达到上述目的:三个方法均以当前进程(即父进程)为视角出发的
i. InputStream Process.getInputStream(); // 获得子进程的标准输出流(到父进程中就是输入流了,对方输出我接受,那么到这里就变成我的输入流了)
ii. InputStream Process.getErrorStream(); // 获得子进程的标准错误流(到父进程中就是输入流了);
iii. OutputStream Process.getOutputStream(); // 获得子进程的标准输入流(在父进程中就是输出流,父进程朝子进程输出,到了子进程就是子进程的输入流了)
!!规律:
a. getInputStream和getOutputStream都是字面意义,同时也是站在父进程角度的,即getInputStream得到的就是输入流,getOutputStream得到的就是输出流;
b. 因此无需死记硬背,输入流就是输入,那必定是对方的输出流,而输出流就是输出,必定到对面就是输入流了,只不过默认绑定的都是对方的标准流;
c. 只有getErrorStream比较特殊,它得到的是对方的错误流,对方的错误流是输出流,那么到了父进程就是输入流了(从返回值可以看出)
4) 示例:getErrorStream的应用(getInputStream和getErrorStream其实是一样的,都是获取子进程的输出)
public class Test {
public static void main(String[] args) throws IOException {
Process p = Runtime.getRuntime().exec("javac"); // 直接调用javac而不带参数是错误的,因此会触发子进程的错误流
try (BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()))) {
String buf = null; // 打印子进程的错误提示信息(注意!是字符形式的)
while ((buf = br.readLine()) != null) {
System.out.println(buf);
}
}
}
}
5) 示例:getOutputStream的应用
public class Test { // 父进程开启子进程,然后用自己的输出来取代子进程的标准输入
public static void main(String[] args) throws IOException {
Process p = Runtime.getRuntime().exec("java ChildTest");
try (PrintStream ps = new PrintStream(p.getOutputStream())) {
ps.println("123456"); // 子进程所谓的“键盘输入”其实是这两句内容
ps.println("lalalala");
}
}
}
class ChildTest { // 子进程从键盘读入然后打印到文件
public static void main(String[] args) throws Exception {
try (
Scanner sc = new Scanner(System.in);
PrintStream ps = new PrintStream(new FileOutputStream("test.out"))
) {
sc.useDelimiter("\n");
while (sc.hasNext()) {
ps.println("keyboard input: " + sc.next());
}
}
}
}