开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情
前言
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。在Java中缓冲流的实现,是与基本流一一对应的,或者换句话说,缓冲流就是在四个基本流的基础上,加入了内存缓冲,大大提高了I/O的效率。按照分类可以分为:
- 4个基本流:
- 字节流
- 字节输入流:FileInputStream
- 字节输出流:FileOutputStream
- 字符流
- 字符输入流:FileReader
- 字符输出流:FileWriter
- 4个缓冲流:
- 字节缓冲流:
- 字节输入缓冲流:BufferedInputStream
- 字节输出缓冲流:BufferedOutputStream
- 字符缓冲流:
- 字符输入缓冲流:BufferedReader
- 字符输出缓冲流:BufferedWriter
一、字节缓冲流
字节缓冲流主要分为字节缓冲输入流和字节缓冲输入流。
public BufferedInputStream(InputStream in)
:创建一个新的缓冲输入流。【通过一个基本的字节流得到一个缓冲流】public BufferedOutputStream(OutputStream out)
:创建一个新的缓冲输出流。功能方法与普通的字节流一致!
基本字节流和缓冲字节流对比
/* 普通字节流复制文件! 将D盘io目录下面的 jdk8.exe文件拷贝到day11_io/src/copy.exe 【文件大小为202MB】 */ public class Test { public static void main(String[] args) { // 创建2个流对象 try ( FileInputStream fis = new FileInputStream("D:/io/jdk8.exe"); FileOutputStream fos = new FileOutputStream("day11_io/src/copy.exe"); ) { long start = System.currentTimeMillis(); // 创建字节数组 byte[] bt = new byte[1024]; int len; while ((len = fis.read(bt)) != -1) { // 写出去 fos.write(bt, 0, len); } long end = System.currentTimeMillis(); System.out.println("复制完毕,消耗时间为:" + (end - start) + "毫秒!"); } catch (IOException e) { e.printStackTrace(); } } }
// 测试结果:1723毫秒!
/* 高效字节流复制文件! 将D盘io目录下面的 jdk8.exe文件拷贝到day11_io/src/copy.exe 【文件大小为202MB】 */ public class Test { public static void main(String[] args) { // 创建2个流对象 try ( BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:/io/jdk8.exe")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("day11_io/src/copy.exe")); ) { long start = System.currentTimeMillis(); // 创建字节数组 byte[] bt = new byte[1024]; int len; while ((len = bis.read(bt)) != -1) { // 写出去 bos.write(bt, 0, len); } long end = System.currentTimeMillis(); System.out.println("复制完毕,消耗时间为:" + (end - start) + "毫秒!"); } catch (IOException e) { e.printStackTrace(); } } }
// 测试结果:413毫秒!
总结:上面对比可以看出字节流和字节缓冲流的用法相同,或者说字节缓冲流需要一个字节流才能创建字节缓冲流,但是在执行效率上字节缓冲流远远优于字节流
二、字符缓冲流
字符缓冲流主要分为字符缓冲输入流和字符缓冲输出流。
public BufferedReader(Reader in)
: 创建一个 新的缓冲输入流。public BufferedWriter(Writer out)
: 创建一个新的缓冲输出流。BufferedReader:public String readLine()
: 读一行文字。BufferedWriter:public void newLine()
: 写一行行分隔符,由系统属性定义符号。
public class Test { public static void main(String[] args) { // 创建2个流对象 try ( BufferedReader br = new BufferedReader(new FileReader("day11_io/src/br.txt")); BufferedWriter bw = new BufferedWriter(new FileWriter("day11_io/src/bw.txt")); ) { // 读到的具体某行数据! String line; while ((line = br.readLine()) != null) { //System.out.println(line); // 将读到的一行数据写到bw.txt文件中 bw.write(line); // 写一行就换行! bw.newLine(); // 等价于:bw.write("rn"); } } catch (IOException e) { e.printStackTrace(); } } }
三、缓冲流练习(文本排序)
需求:将下列文件数据恢复顺序
3.侍中、侍郎郭攸之、费祎、董允等,此皆良实,志虑忠纯,是以先帝简拔以遗陛下。愚以为宫中之事,事无大小,悉以咨之,然后施行,必得裨补阙漏,有所广益。
8.愿陛下托臣以讨贼兴复之效,不效,则治臣之罪,以告先帝之灵。若无兴德之言,则责攸之、祎、允等之慢,以彰其咎;陛下亦宜自谋,以咨诹善道,察纳雅言,深追先帝遗诏,臣不胜受恩感激。
4.将军向宠,性行淑均,晓畅军事,试用之于昔日,先帝称之曰能,是以众议举宠为督。愚以为营中之事,悉以咨之,必能使行阵和睦,优劣得所。
2.宫中府中,俱为一体,陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。
1.先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。
9.今当远离,临表涕零,不知所言。
6.臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间,尔来二十有一年矣。
7.先帝知臣谨慎,故临崩寄臣以大事也。受命以来,夙夜忧叹,恐付托不效,以伤先帝之明,故五月渡泸,深入不毛。今南方已定,兵甲已足,当奖率三军,北定中原,庶竭驽钝,攘除奸凶,兴复汉室,还于旧都。此臣所以报先帝而忠陛下之职分也。至于斟酌损益,进尽忠言,则攸之、祎、允之任也。
5.亲贤臣,远小人,此先汉所以兴隆也;亲小人,远贤臣,此后汉所以倾颓也。先帝在时,每与臣论此事,未尝不叹息痛恨于桓、灵也。侍中、尚书、长史、参军,此悉贞良死节之臣,愿陛下亲之信之,则汉室之隆,可计日而待也。
- 分析:
① 创建文本数据对应的字符缓冲流对象
② 循环读取每一行(readLine),得到的是字符串数据!
③ 使用字符串的split方法以 . 进行切割!得到字符串数组(0索引是字符串序号,1索引是字符串文字)
④ 在循环外部创建Map(TreeMap),在遍历里面将字符串序号作为key,字符串文字作为value,添加到map集合
⑤ 遍历Map,将key和value拼接为一个新的字符串 \ - 作业:
将map里面的数据写出到一个文件中!
public class Test { public static void main(String[] args) { // 1. 创建1个字符高效流对象 try ( BufferedReader br = new BufferedReader(new FileReader("day11_io/src/br.txt")); ) { // 4. 定义一个Map集合 TreeMap<String, String> map = new TreeMap<>(); // 2.循环读到的具体某行数据! String line; while ((line = br.readLine()) != null) { // 3. 切割字符串的数据 String[] split = line.split("."); // 5. 将字符串序号作为key,字符串文字作为value,添加到map集合 map.put(split[0], split[1]); } // 6. 遍历map for (String key : map.keySet()) { System.out.println(key + "." + map.get(key)); } } catch (IOException e) { e.printStackTrace(); } } }
后记
在日常开发过程中我们使用缓冲流进行操作文件还是比较常见的,应该牢牢掌握。
喜欢我的文章的朋友点点喜欢、收藏,也欢迎朋友们评论区留下你的意见和建议,恕毅在此拜谢!