缓冲流
Posted anke-z
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了缓冲流相关的知识,希望对你有一定的参考价值。
缓冲流
学习了基本的一些流,作为IO流的入门,今天我们要见识一些更强大的流。比如能够高效读写的缓冲流,能够转换编码的转换流,能够持久化存储对象的序列化流等等。这些功能更为强大的流,都是在基本的流对象基础之上创建而来的,就像穿上铠甲的武士一样,相当于是对基本流对象的一种增强。
1.1 概述
缓冲流,也叫高效流,是对4个基本的FileXxx
流的增强,所以也是4个流,按照数据类型分类:
- 字节缓冲流:
BufferedInputStream
,BufferedOutputStream
- 字符缓冲流:
BufferedReader
,BufferedWriter
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。
1.2 字节缓冲
字节缓冲输出流
java.io.BufferedOutputStream extends OutputStream
BufferedOutputStream:字节缓冲输出流
继承自父类的共性方法:
- public void close():关闭此输出流并释放与此资源相关的任何系统资源
- void
void write(byte[] b)
将b.length
个字节从指定的 byte 数组写入此输出流void
write(byte[] b, int off, int len)将指定 byte 数组中从偏移量
off开始的
len个字节写入此输出流。abstract void
write(int b)
将指定的字节写入此输出流
构造方法
BufferedOutputStream(OutputStream out)
创建一个新的缓冲输出流,以将数据写入指定的底层输出流。- BufferedOutputStream(OutputStream out, int size) 创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。
参数:
- outputStream out:字节输出流
- 我们可以传递FileOutputStream,缓冲流会给FileoutputStream增加一个缓冲区,提高FileOutputStream的写入效率
- int size:指定缓冲流内部缓冲区的大小,不指定默认
使用步骤(重点)
- 创建FileOutputStream对象,构造方法中绑定要输入的目的地
- 创建BufferedOutputStream对象,构造方法中传递FileOutputStream对象,提高FileOutputStream对象效率
- 使用BufferedOutputStream对象中的方法write,把数据写入到内部缓冲区
- 使用BufferedOutputStream对象中的方法flush,把内部缓冲区中的数据,刷新到文件中
- 释放资源(会先调用flush方法刷新数据,第4部可以省略)
示例代码:
public static void main(String[] args) throws IOException {
// 1. 创建FileOutputStream对象,构造方法中绑定要输入的目的地
FileOutputStream fos = new FileOutputStream("D:Testg.txt");
// 2. 创建BufferedOutputStream对象,构造方法中传递FileOutputStream对象,提高FileOutputStream对象效率
BufferedOutputStream bos = new BufferedOutputStream(fos);
// 3. 使用BufferedOutputStream对象中的方法write,把数据写入到内部缓冲区
bos.write("把数据写到缓冲区".getBytes());
// getBytes():把字符串转换为字节数组
// 4. 使用BufferedOutputStream对象中的方法flush,把内部缓冲区中的数据,刷新到文件中
bos.flush();
// 5. 释放资源(会先调用flush方法刷新数据,第4部可以省略)
bos.close();
}
字节缓冲输入流
BufferedInputStream:字节缓冲输入流
java.io.BufferedInputStream extends InputStream
继承父类的成员方法
- int read() 从输入流中读取数据的下一个字节
- int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区b中
- void close() 关闭此输入流并释放与该流相关联的所有系统资源
构造方法
- BufferedInputStream(InputStream in) 创建具有指定缓冲区大小的
BufferedInputStream
并保存其参数,即输入流in
,以便将来使用 - BufferedInputStream(InputStream in int size) 创建具有指定缓冲区大小的
BufferedInputStream
并保存其参数,即输入流in
,以便将来使用 - 参数:
- InputStream in:字节输入流
- 我们可以传递FileInputSrteam,缓冲流会给FileInputStream增加一个缓冲区,提高FileInputStream的读取效率
- int size :指定缓冲流内部缓冲区的大小,不指定默认
- InputStream in:字节输入流
使用步骤(重点)
- 创建FileInputStream对象,构造方法中绑定要读取的数据源
- 创建BuffreedInputStream对象,构造方法中传递FileInputStream对象,提高FileInputStream对象的读取效率
- 使用BufferedInputStream对象中的方法read,读取文件
- 释放资源
示例代码
public static void main(String[] args) throws IOException {
// 1. 创建FileInputStream对象,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream("D:Testg.txt");
// 2. 创建BuffreedInputStream对象,构造方法中传递FileInputStream对象,提高FileInputStream对象的读取效率
BufferedInputStream bis = new BufferedInputStream(fis);
// 3. 使用BufferedInputStream对象中的方法read,读取文件
// int read() 从输入流中读取数据的下一个字节
/*int len = 0;
// 记录读取到的有效字节个数
while ((len = bis.read())!=-1){
System.out.println(len);
}*/
// int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区b中
// 记录每次读取到的有效字节
int len = 0;
// 存储每次读取到的数据
byte[] bytes = new byte[1024];
while ((len = bis.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}
bis.close();
}
效率测试
查询API,缓冲流读写方法与基本的流是一致的,我们通过复制文件,测试它的效率。
基本流
代码如下
public static void main(String[] args) throws IOException {
long s = System.currentTimeMillis();
// 1. 创建一个字节输入流对象,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream("c:Test1.jpg");
// 2. 创建一个字节输出流对象,构造方法中绑定要写入的目的地
FileOutputStream fos = new FileOutputStream("d:Test1.jpg");
// 3. 使用字节输入流对象中的方法read读取文件
// 一次读取一个字节写入一个字节的方式
/*int len = 0;
while ((len = fis.read())!= -1){
// 4. 使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
fos.write(len);
}*/
// 使用数组缓冲区读取多个字节,写入多个字节
byte[] bytes = new byte[1024];
// 3.使用字节输入流对象中的方法read读取文件
int len = 0;
while ((len = fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
// 每次读取字节的个数
// 5. 释放资源(先关写的,后关读的,如果写完了,肯定读取完毕了)
fos.close();
fis.close();
long e = System.currentTimeMillis();
System.out.println("程序运行时间:"+(e-s)+"毫秒");
}
}
// 运行结果
文件大小:2,629,730 字节
使用字节输入输出流耗时:14179毫秒
添加个数组 使用字节输入输出流耗时:74毫秒
缓冲流
代码如下
public static void main(String[] args) throws IOException {
long s = System.currentTimeMillis();
// 创建字节缓冲输入流对象
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("c:Test1.jpg"));
// 创建字节缓冲输出流对象
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d:Test1.jpg"));
/*// 使用字节输入流的read方法读取文件
int len = 0;
while ((len = bis.read())!=-1){
bos.write(len);
}*/
// 使用数组方法
byte[] bytes = new byte[1024];
int len = 0;
while ((len = bis.read(bytes))!=-1){
bos.write(bytes,0,len);
}
bos.close();
bis.close();
long t = System.currentTimeMillis();
System.out.println("复制耗费的时间:"+(t-s)+"毫秒");
}
}
// 运行结果
文件大小:2,629,730 字节
使用字节缓冲输入输出流耗时:155毫秒
添加个数组 使用字节缓冲输入输出流耗时:8毫秒
1.3 字符缓冲流
构造方法
public BufferedReader(Reader in)
:创建一个 新的缓冲输入流。public BufferedWriter(Writer out)
: 创建一个新的缓冲输出流。
构造举例,代码如下:
// 创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("br.txt"));
// 创建字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
特有方法
字符缓冲流的基本方法与普通字符流调用方式一致,不再阐述,我们来看它们具备的特有方法。
- BufferedReader:
public String readLine()
: 读一行文字。 - BufferedWriter:
public void newLine()
: 写一行行分隔符,由系统属性定义符号。
readLine
方法演示,代码如下:
public class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
// 创建流对象
BufferedReader br = new BufferedReader(new FileReader("in.txt"));
// 定义字符串,保存读取的一行文字
String line = null;
// 循环读取,读取到最后返回null
while ((line = br.readLine())!=null) {
System.out.print(line);
System.out.println("------");
}
// 释放资源
br.close();
}
}
newLine
方法演示,代码如下:
public class BufferedWriterDemo throws IOException {
public static void main(String[] args) throws IOException {
// 创建流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt"));
// 写出数据
bw.write("黑马");
// 写出换行
bw.newLine();
bw.write("程序");
bw.newLine();
bw.write("员");
bw.newLine();
// 释放资源
bw.close();
}
}
输出效果:
黑马
程序
员
1.4 练习:文本排序
请将文本信息恢复顺序。
3.侍中、侍郎郭攸之、费祎、董允等,此皆良实,志虑忠纯,是以先帝简拔以遗陛下。愚以为宫中之事,事无大小,悉以咨之,然后施行,必得裨补阙漏,有所广益。
8.愿陛下托臣以讨贼兴复之效,不效,则治臣之罪,以告先帝之灵。若无兴德之言,则责攸之、祎、允等之慢,以彰其咎;陛下亦宜自谋,以咨诹善道,察纳雅言,深追先帝遗诏,臣不胜受恩感激。
4.将军向宠,性行淑均,晓畅军事,试用之于昔日,先帝称之曰能,是以众议举宠为督。愚以为营中之事,悉以咨之,必能使行阵和睦,优劣得所。
2.宫中府中,俱为一体,陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。
1.先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。
9.今当远离,临表涕零,不知所言。
6.臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间,尔来二十有一年矣。
7.先帝知臣谨慎,故临崩寄臣以大事也。受命以来,夙夜忧叹,恐付托不效,以伤先帝之明,故五月渡泸,深入不毛。今南方已定,兵甲已足,当奖率三军,北定中原,庶竭驽钝,攘除奸凶,兴复汉室,还于旧都。此臣所以报先帝而忠陛下之职分也。至于斟酌损益,进尽忠言,则攸之、祎、允之任也。
5.亲贤臣,远小人,此先汉所以兴隆也;亲小人,远贤臣,此后汉所以倾颓也。先帝在时,每与臣论此事,未尝不叹息痛恨于桓、灵也。侍中、尚书、长史、参军,此悉贞良死节之臣,愿陛下亲之信之,则汉室之隆,可计日而待也。
案例分析
- 逐行读取文本信息。
- 解析文本信息到集合中。
- 遍历集合,按顺序,写出文本信息。
案例实现
public class BufferedTest {
public static void main(String[] args) throws IOException {
// 创建map集合,保存文本数据,键为序号,值为文字
HashMap<String, String> lineMap = new HashMap<>();
// 创建流对象
BufferedReader br = new BufferedReader(new FileReader("in.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt"));
// 读取数据
String line = null;
while ((line = br.readLine())!=null) {
// 解析文本
String[] split = line.split(".");
// 保存到集合
lineMap.put(split[0],split[1]);
}
// 释放资源
br.close();
// 遍历map集合
for (int i = 1; i <= lineMap.size(); i++) {
String key = String.valueOf(i);
// 获取map中文本
String value = lineMap.get(key);
// 写出拼接文本
bw.write(key+"."+value);
// 写出换行
bw.newLine();
}
// 释放资源
bw.close();
}
}
以上是关于缓冲流的主要内容,如果未能解决你的问题,请参考以下文章