I/O高级流
经过我们之前的学习,我们对IO流的一些基本流如字节流和字符流都学习完毕了。
而在IO流的整个大体系中,他除了一些基本流的操作,他还有一些高级流等待着我们来解锁。
所以话不多说,今天我们先来学习其中一种高级流——缓冲流。
缓冲流
缓冲流,也叫高效流,是对输出和输入流的增强。
缓冲流的分类
缓冲流的基本原理
在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。
字节缓冲流
1. 构造方法
public BufferedInputStream(InputStream in)
:创建一个 新的缓冲输入流,需要传入一个InputStream
类型参数。
-
public BufferedOutputStream(OutputStream out)
: 创建一个新的缓冲输出流,需要传入一个OutputStream
类型参数。演示如下:
public class BufferedTest { public static void main(String[] args) throws FileNotFoundException { //构造方式一: 创建字节缓冲输入流【但是开发中一般常用下面的格式申明】 FileInputStream fps = new FileInputStream("e:\\demo\\b.txt"); BufferedInputStream bis = new BufferedInputStream(fps); //构造方式一: 创建字节缓冲输入流 BufferedInputStream bis2 = new BufferedInputStream(new FileInputStream("e:\\demo\\b.txt")); //构造方式二: 创建字节缓冲输出流 FileOutputStream fos = new FileOutputStream("e:\\demo\\b.txt"); BufferedOutputStream bos = new BufferedOutputStream(fos); //构造方式二: 创建字节缓冲输出流 BufferedOutputStream bos2 = new BufferedOutputStream(new FileOutputStream("e:\\demo\\b.txt")); } } 复制代码
2. 感受高效
既然称缓冲流为高效流,那我们不得测试下看看,是骡子是马得拉出来溜溜啊。
先来感受下:
public class BufferedTest2 {
public static void main(String[] args) {
//使用多线程的方式来同时测试两者复制的速度。
new Thread(() -> oldCopy()).start();//这个是JDK8新特性中的Lambda表达式
new Thread(() -> bufferedCopy()).start();
/*
原样相当于:
new Thread(new Runnable() {
@Override
public void run() {
oldCopy();
}
}).start();
*/
}
public static void oldCopy() {
// 记录开始时间
long start = System.currentTimeMillis();
// 创建流对象
try (
FileInputStream fis = new FileInputStream("e:\\demo\\科比演讲.mp4");
FileOutputStream fos = new FileOutputStream("e:\\demoCopy\\oldCopy.mp4")
){
// 读写数据
int b;
while ((b = fis.read()) != -1) {
fos.write(b);
}
} catch (IOException e) {
e.printStackTrace();
}
// 记录结束时间
long end = System.currentTimeMillis();
System.out.println("普通流复制时间:"+(end - start)+" 毫秒");
}
public static void bufferedCopy() {
// 记录开始时间
long start = System.currentTimeMillis();
// 创建流对象
try (
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("e:\\demo\\科比演讲.mp4"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("e:\\demoCopy\\newCopy.mp4"));
){
// 读写数据
int b;
while ((b = bis.read()) != -1) {
bos.write(b);
}
} catch (IOException e) {
e.printStackTrace();
}
// 记录结束时间
long end = System.currentTimeMillis();
System.out.println("缓冲流复制时间:"+(end - start)+" 毫秒");
}
}
运行结果:
缓冲流复制时间:3498 毫秒
普通流复制时间:319839 毫秒
复制代码
程序运行后,可以深刻的体验到缓冲流的快速,缓冲流已经复制成功了,但是普通流还没成功。不止没成功,而且耗时超级久。可以感受到缓冲流是普通流的几十倍了吧。我这个视频仅仅是46.2M大小而已,如果是更大的文件,几百M更甚至是几G的文件呢?那我岂不是一天都没办法传输完成了。这岂不是很百度网盘?
是不是觉得还不够快,想体验飞一般的感觉。现在我带你冲上云顶。嘿嘿,老司机要开车了 ,不要晕车哦。
接下来使用数组的方式进行体验:
public class BufferedTest3 {
public static void main(String[] args) {
//使用多线程的方式来同时测试两者复制的速度。
new Thread(() -> oldCopy()).start();
new Thread(() -> bufferedCopy()).start();
}
public static void oldCopy() {
//开始时间
long start = System.currentTimeMillis();
try(
FileInputStream fis = new FileInputStream("e:\\demo\\科比演讲.mp4");
FileOutputStream fos = new FileOutputStream("e:\\demoCopy\\oldCopy2.mp4");
) {
int len;
byte[] b = new byte[1024];
while((len = fis.read(b)) != -1) {
fos.write(b, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
//结束时间
long end = System.currentTimeMillis();
System.out.println("普通流数组复制时间:" + (end - start) + "毫秒");
}
public static void bufferedCopy() {
//开始时间
long start = System.currentTimeMillis();
// 创建流对象
try (
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("e:\\demo\\科比演讲.mp4"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("e:\\demoCopy\\newCopy2.mp4"));
){
// 读写数据
int len;
byte[] bytes = new byte[1024];
while ((len = bis.read(bytes)) != -1) {
bos.write(bytes, 0 , len);
}
} catch (IOException e) {
e.printStackTrace();
}
// 结束时间
long end = System.currentTimeMillis();
System.out.println("缓冲流使用数组复制时间:"+(end - start)+" 毫秒");
}
}
程序执行结果:
缓冲流使用数组复制时间:370 毫秒
普通流数组复制时间:1016毫秒
复制代码
是不是这个车速更快了,如果还不够快,你可以把 byte[] bytes = new byte[1024]
改为 byte[] bytes = new byte[1024*8]
。可以让你体验到更高效。你就会感觉这速度飞上天了。
字符缓冲流
1. 构造方法
-
public BufferedReader(Reader in)
:创建一个 新的缓冲输入流,传入参数的类型为Reader
。 -
public BufferedWriter(Writer out)
: 创建一个新的缓冲输出流,传入参数的类型为Writer
。演示如下:
// 创建字符缓冲输入流 BufferedReader br = new BufferedReader(new FileReader("e:\\demo\\b.txt")); // 创建字符缓冲输出流 BufferedWriter bw = new BufferedWriter(new FileWriter("e:\\demo\\b.txt")); 复制代码
2. 特有方法
不用于字节缓冲流和字符普通流来说,他有别人所没有的东西,那是什么呢,我们现在来看看:
-
字符缓冲输入流
BufferedReader
:public String readLine()
: 读一行文字,如果读到最后,则会返回NULL
。 -
字符缓冲输出流
BufferedWriter
:public void newLine()
: 写一行行分隔符即换行,由系统属性定义符号。一步一步来演示下:
-
public void newLine()
:public class BufferedTest4 { public static void main(String[] args) throws IOException { BufferedWriter bw = new BufferedWriter(new FileWriter("e:\\demo\\hello.txt")); //写出数据 bw.write("Hello"); //换行 //public void newLine() bw.newLine(); bw.write("world"); bw.newLine(); bw.write("Java"); bw.newLine(); bw.write("newLine"); bw.flush(); bw.close(); } } 程序执行后,查看hello.txt信息为: Hello world Java newLine 复制代码
-
public String readLine()
:public class BufferedTest5 { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new FileReader("e:\\demo\\hello.txt")); //定义获取字符串 String line = null; while((line = br.readLine()) != null) { System.out.println(line); } br.close(); } } 程序执行后,查看hello.txt信息为: Hello world Java newLine 复制代码
-
文本排序案例
文本排序练习什么呢,下面我分享我比较喜欢的一首,然后按一定的顺序乱排。当然不要担心,肯定有办法让你可以重新排序的。
8.既然目标是地平线
7.我不去想身后会不会袭来寒风冷雨
3.便只顾风雨兼程
9.留给世界的只能是背影
4.我不去想能否赢得爱情
5.既然钟情于玫瑰
6.就勇敢地吐露真诚
10.我不去想未来是平坦还是泥泞
11.只要热爱生命
12.一切,都在意料之中
5.既然钟情于玫瑰
6.就勇敢地吐露真诚
1.我不去想是否能够成功
2.既然选择了远方
复制代码
<热爱生命>
来自汪国真的诗集里头,说实话,这篇我在高中的作文中,一直被我拿来引用。不止这一篇吧,还有汪国真的<感谢>
等。虽然作文至今也没有拿到特别高的分,但也不能妨碍我对汪国真的作品的热爱。正如我原想收获一缕春风,你却给了我整个夏天。你要相信你的才华不会永远被埋没。所以当我们跨越了一座高山,也就是跨越了一个真实的自己。
好了,Stop
,说回重点吧:我们要如何把这篇诗排序呢。
分析:
-
我们不是刚学了一个字符缓冲流中读取一行的吗,那我们就可以先读取每一行文字。
-
然后不得去解析文字吗,我们用前一两位排?但是如果我文本一多,有几百行呢,不就是三位数了吗,显示这种方法不可取的。
-
我们应该可以看到在序号的后面有个字符
"."
,我们可以用这个缺陷来入手。然后将拆分后的序号和文字存储到集合中,这种有CP
组合的,我们就可以采用Map
集合啦。 -
然后再将排好序的文字,重新写入到文件中把。
-
OK
,既然知道了思路,我们就一起大干一场吧:public class BufferedTest6 { public static void main(String[] args) throws IOException { //创建字符输入流对象 BufferedReader br = new BufferedReader(new FileReader("e:\\demo\\热爱生命.txt")); //创建字符输出流对象 BufferedWriter bw = new BufferedWriter(new FileWriter("e:\\demoCopy\\热爱生命.txt")); //创建Map集合,用于保存将来得到的数据,键为序号,值为文本。 HashMap<String, String> map = new HashMap<>(); //读取数据 String line = null; while((line = br.readLine()) != null) { //通过.来分割文本和序号 String[] split = line.split("\\."); //将得到的数据存入集合中 map.put(split[0], split[1]); } //接下来不就是可以按序号即键找值的方式来得到文本吗 for (int i = 1; i <= map.size(); i++) { String key = String.valueOf(i); //键找值 String value = map.get(key); //得到文本,这里我序号还是写进去,怕你觉得我懵你,如果相信我的同学,可以不用写序号了。 bw.write(key + "." + value); if(i == 7){ System.out.println(value); } //bw.write(value); bw.newLine(); bw.flush(); } bw.flush(); //释放资源 bw.close(); br.close(); } } 复制代码
程序运行后,正如一切都在意料之中,查看文件可以看到:
1.我不去想是否能够成功 2.既然选择了远方 3.便只顾风雨兼程 4.我不去想能否赢得爱情 5.既然钟情于玫瑰 6.就勇敢地吐露真诚 7.我不去想身后会不会袭来寒风冷雨 8.既然目标是地平线 9.留给世界的只能是背影 10.我不去想未来是平坦还是泥泞 11.只要热爱生命 12.一切,都在意料之中 复制代码
如果不想有序号了,可以选择不写入序号。
总结
相信各位看官都对IO流中高级流中的缓冲流类有了一定了解,期待等待下一章的高级流——转换流教学吧!
当然还有很多流等着下次一起看吧!欢迎期待下一章的到来!
学到这里,今天的世界打烊了,晚安!虽然这篇文章完结了,但是我还在,永不完结。我会努力保持写文章。来日方长,何惧车遥马慢!
感谢各位看到这里!愿你韶华不负,青春无悔!
注: 如果文章有任何错误和建议,请各位大佬尽情留言!如果这篇文章对你也有所帮助,希望可爱亲切的您给个三连关注下,非常感谢啦!
作者:***爷哪吒
链接:https://juejin.cn/post/6994718043582496805
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。