[疯狂Java]I/O:标准流重定向、JVM读写其它进程数据

本文介绍了Java中标准输入输出流的概念,包括System.in、System.out和System.err,并详细阐述了如何通过System类的静态方法进行标准流重定向。此外,还探讨了JVM如何读写其他进程数据,特别是通过Process对象的方法实现父子进程间的通信,如getInputStream、getErrorStream和getOutputStream的使用,以实现数据交换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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());
			}
		}
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值