博主学了打印流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方法的使用规则和原理了。
希望我踩的这个坑能够帮助到你们(*^▽^*)。