记一次java的System类setOut方法改变输出流向失效问题的解决方法

mac2022-06-30  60

博主学了打印流PrintStream后做了个小练习,功能就是往文件b.txt中打印一个字符串,并且利用System类的setOut方法改变标准输出流的流向,将另一个文件a.txt里的内容读取出来打印到控制台显示,,下面上代码↓

/* 将a.txt打印到控制台,同时往文件中打印一句字符串 */ public static void printStreamDemo() throws IOException { //创建字节缓冲输入流读取文件内容到内存 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt")); //定义字节数组作为缓冲区接收每次读取到的有效字节,提高读取效率 byte[] bytes = new byte[1024]; //初始化一个变量len接收每次读取到的有效字节个数 int len = 0; //声明一个打印流,避免变量作用域导致无法关流的问题 PrintStream ps = null; //读取文件数据 while ((len = bis.read(bytes)) != -1) { //构造一个带自动刷新的打印流,打印到文件 ps = new PrintStream(new FileOutputStream("b.txt"), true); //使输出流的流向为文件 System.setOut(ps); //打印一句话到文件,且不换行 System.out.print("这句话是输出到b.txt文件的"); //构造一个带自动刷新的打印流,打印到控制台 ps = new PrintStream(System.out, true) //改变输出的流向为控制台,开启自动刷新 System.setOut(ps); //将读取到的有效字节打印到控制台,且不换行 System.out.print(new String(bytes, 0, len)); } //释放资源 if(ps!=null){ ps.close(); } bis.close(); }

a.txt里面有一段文字↓

这段文字怎么看起来这么熟悉?没错,就是杰伦的发如雪(手动滑稽),而b.txt则是一个空文本。

然而程序的执行结果如下:

是的,你没有看错,控制台什么都没有显示,很显然输出流的流向并没与被改变成打印到控制台,那么控制台没有的话那个字符串打印到哪儿去了呢?我们把打印的目的地文件b.txt打开看一下↓

对于这个问题,博主尝试了很多种方法去排错,用debug一行行走也没找出问题,也看了setOut的源码,但是终究没能弄明白其中的原因,但是博主尝试把PrintStream定义到外面时,里面setOut方法直接传入后,运行发现这回正确了↓

/* 将a.txt打印到控制台,同时往文件中打印一句字符串 */ public static void printStreamDemo() throws IOException { //创建字节缓冲输入流读取文件内容到内存 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt")); //定义字节数组作为缓冲区接收每次读取到的有效字节,提高读取效率 byte[] bytes = new byte[1024]; //定义len接收每次读取到的有效字节个数 int len = 0; //创建带自动刷新的打印流,打印到文件 PrintStream ps = new PrintStream(new FileOutputStream("b.txt"), true); //创建带自动刷新的打印流,打印到控制台 PrintStream out = new PrintStream(System.out, true); //读取文件数据 while ((len = bis.read(bytes)) != -1) { //使输出的内容的目的地为文件 System.setOut(ps); //打印一句话到文件,且不换行 System.out.print("这句话是输出到b.txt文件的"); //使输出的内容的目的地为控制台 System.setOut(out); //将读取到的有效字节打印到控制台 System.out.print(new String(bytes, 0, len)); } //释放资源 ps.close(); bis.close(); }

运行结果↓

原因:

之前没有打印到控制台的原因是因为博主使用ps=new PrintStream(System.out,true)时,里面的参数System.out仍然获取到的是文件的输出流向,因为在这行执行之前当前输出流就已经被setOut为输出到文件了,所以第二次setOut(ps)并没有改变任何输出的流向,仍然往文件中打印,那么为什么将其定义在外面就可以了呢?因为在循环外时我们还没有将输出流的流向setOut为输出到文件,所以PrintStream out = new PrintStream(System.out,true)中的System.out获取的是默认的打印打控制台的流向,然后分别设置到两个打印流的setOut流向,这样才解决了这个问题。

总结:

System.out是默认往控制台打印,它代表当前设备的标准输出流流向,但是并不是写死的往控制台打印,它可以通过System的静态方法setOut改变其流向,同理我们也就推出了System.in和System.SetIn方法的使用规则和原理了。

希望我踩的这个坑能够帮助到你们(*^▽^*)。

最新回复(0)