缓冲流
- 1. 概述
- 2. 作用
- 3. 字节缓冲流
- 3.1 构造方法
- 3.2 代码示例
- 4. 字符缓冲流
- 4.1 构造方法
- 4.2 特有方法
- 4.3 代码示例
- 4.3.1 `readline()`方法示例
- 4.3.2 `newline()`方法示例
- 5. 字节缓冲流提高效率的原理
- 6. 注意事项
文章中的部分照片来源于哔站
黑马程序员阿伟老师
处,仅用学习,无商用,侵权联系删除!
1. 概述
缓冲流
(Buffered stream)是指在输入输出流的基础上加入了缓冲机制,通过缓冲来提高读写性能的一种流。
在进行数据读写时,缓冲流会先将数据暂存在缓冲区
中,当缓冲区
满了或者达到一定条件时才会将数据写入到文件或从文件中读取数据,这样就减少了实际的读写次数,提高了读写效率。
使用缓冲流可以有效地减少对磁盘的访问次数,避免频繁的IO操作,从而改善程序的性能。
原理:底层自带了长度为8192
的缓冲区提高性能
常见的缓冲流包括
BufferedInputStream
和BufferedOutputStream
(用于字节流)以及BufferedReader
和BufferedWriter
(用于字符流)等。
2. 作用
-
提高IO效率:缓冲流可以减少实际的读写次数,通过一次性读取或写入更多的数据到缓冲区中,减少了对磁盘或网络的访问次数,从而提高IO效率。
-
减少系统开销:频繁的IO操作会给系统带来较大的开销,而使用缓冲流可以减少IO操作的频率,降低了系统的开销,提升程序的性能。
-
提供便捷的操作方法:缓冲流提供了许多便捷的读写方法,如readLine()、write()等,使得读写操作更加方便和灵活。
-
自动管理缓冲区:缓冲流会自动管理缓冲区的大小和数据的读写,程序员无需手动管理缓冲区,简化了编程过程。
3. 字节缓冲流
3.1 构造方法
方法名称 | 说明 |
---|---|
public BufferedInputStream(InputStream is) | 把基本流包装成高级流,提高读取数据的性能 |
public BufferedOutputStream(OutputStream os) | 把基本流包装成高级流,提高写出数据的性能 |
BufferedInputStream
和 BufferedOutputStream
是 Java 中用于提高IO读写性能的缓冲流。它们分别用于包装输入流和输出流,使用了内部缓冲区来优化读写操作。
-
BufferedInputStream:
BufferedInputStream
继承自FilterInputStream
,通过将输入流包装在其中,并在内部维护一个字节数组作为缓冲区,实现了对数据的高效读取操作。- 当从
BufferedInputStream
中读取数据时,它会优先从缓冲区中读取数据,只有当缓冲区为空时才会从基础输入流中读取新的数据到缓冲区,这减少了对基础输入流的实际读取次数,提高了读取性能。
举例:
try (FileInputStream fis = new FileInputStream("input.txt"); BufferedInputStream bis = new BufferedInputStream(fis)) { int data = bis.read(); // 从缓冲流中读取数据 while (data != -1) { System.out.print((char) data); data = bis.read(); } } catch (IOException e) { e.printStackTrace(); }
-
BufferedOutputStream:
BufferedOutputStream
继承自FilterOutputStream
,通过将输出流包装在其中,并在内部维护一个字节数组作为缓冲区,实现了对数据的高效写入操作。- 当向
BufferedOutputStream
中写入数据时,它会先将数据写入到缓冲区中,只有当缓冲区满了或者调用flush()
方法时才会将缓冲区中的数据实际写入到基础输出流中,减少了对基础输出流的实际写入次数,提高了写入性能。
举例:
try (FileOutputStream fos = new FileOutputStream("output.txt"); BufferedOutputStream bos = new BufferedOutputStream(fos)) { String message = "Hello, BufferedOutputStream!"; byte[] bytes = message.getBytes(); bos.write(bytes); // 将数据写入到缓冲流中 bos.flush(); // 刷新缓冲区,将数据写入到文件中 } catch (IOException e) { e.printStackTrace(); }
3.2 代码示例
-
代码示例1
需求: 利用字节缓冲流拷贝文件(一次读取一个字节)package text.IOStream.BufferedStream.BufferedStream01; import java.io.*; /*字节缓冲流 | 方法名称 | 说明 | | -------------------------------------------- | ---------------------------------------- | | public BufferedInputStream(InputStream is) | 把基本流包装成高级流,提高读取数据的性能 | | public BufferedOutputStream(OutputStream os) | 把基本流包装成高级流,提高写出数据的性能 | 需求: 利用字节缓冲流拷贝文件(一次读取一个字节) */ public class BufferedStream01 { public static void main(String[] args) throws IOException { //创建缓冲流对象 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\JavaCode\\code\\codeText01\\src\\text\\IOStream\\BufferedStream\\BufferedStream01\\a.txt")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\JavaCode\\code\\codeText01\\src\\text\\IOStream\\BufferedStream\\BufferedStream01\\b.txt")); //读取数据(一次读取一个字节) int b; while ((b = bis.read()) != -1) { bos.write((char) b); } //释放资源 bos.close(); bis.close(); } }
-
输出结果
- a.txt
- b.txt
- a.txt
-
代码示例2
需求:利用字节缓冲流拷贝文件(一次读取一个字节数组)package text.IOStream.BufferedStream.BufferedStream02; import java.io.*; /*字节缓冲流 | 方法名称 | 说明 | | -------------------------------------------- | ---------------------------------------- | | public BufferedInputStream(InputStream is) | 把基本流包装成高级流,提高读取数据的性能 | | public BufferedOutputStream(0utputStream os) | 把基本流包装成高级流,提高写出数据的性能 | 需求: 利用字节缓冲流拷贝文件(一次读取一个字节数组) */ public class BufferedStream02 { public static void main(String[] args) throws IOException { //创建缓冲流对象 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\JavaCode\\code\\codeText01\\src\\text\\IOStream\\BufferedStream\\BufferedStream02\\a.txt")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\JavaCode\\code\\codeText01\\src\\text\\IOStream\\BufferedStream\\BufferedStream02\\b.txt")); //读取数据(一次读取一个字节数组) byte[] bytes = new byte[1024]; int b; //定义变量记录每次读取的有效的数据个数 while ((b = bis.read(bytes)) != -1) { bos.write(bytes, 0, b); } //释放资源 bos.close(); bis.close(); } }
-
输出结果
- a.txt
- b.txt
- a.txt
4. 字符缓冲流
4.1 构造方法
方法名称 | 说明 |
---|---|
public BufferedReader(Reader) | 将基本字符输入流包装成缓冲字符输入流,以提高读取效率。 |
public BufferedWriter(Writer) | 将基本字符输出流包装成缓冲字符输出流,以提高写入效率。 |
-
BufferedReader:
-
BufferedReader
是 Java 中用于提供缓冲字符输入流的类。它继承自Reader
类,通过包装基本的字符输入流,如FileReader
或InputStreamReader
,并添加缓冲功能,以提高读取字符数据的效率。 -
举例:以下是一个简单示例,演示如何使用
BufferedReader
从文件中读取数据:try (FileReader fileReader = new FileReader("example.txt"); BufferedReader bufferedReader = new BufferedReader(fileReader)) { String line; while ((line = bufferedReader.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); }
-
-
BufferedWriter:
-
BufferedWriter
是 Java 中用于提供缓冲字符输出流的类。它继承自Writer
类,通过包装基本的字符输出流,如FileWriter
或OutputStreamWriter
,并添加缓冲功能,以提高写入字符数据的效率。 -
举例:以下是一个简单示例,演示如何使用
BufferedWriter
将数据写入文件:try (FileWriter fileWriter = new FileWriter("output.txt"); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)) { bufferedWriter.write("Hello, WeTab!"); bufferedWriter.newLine(); bufferedWriter.write("Welcome to the world of AI."); } catch (IOException e) { e.printStackTrace(); }
-
4.2 特有方法
- 字符缓冲输入流特有方法
字符缓冲输入流特有方法 | 说明 |
---|---|
public string readLine() | 读取一行数据,如果没有数据可读了,会返回null |
- 细节:
readLine()
方法在读取的时候,一次读一整行,遇到回车换行结束,但是他不会把回车换行读到内存当中
- 字符缓冲输出流特有方法
字符缓冲输出流特有方法 | 说明 |
---|---|
public void newLine() | 跨平台的换行 |
4.3 代码示例
4.3.1 readline()
方法示例
- 代码示例
package text.IOStream.BufferedStream.BufferedStream03; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; /* 字符缓冲流 字符缓冲流的构造方法 | 方法名称 | 说明 | | ----------------------------- | ------------------ | | public BufferedReader(Reader) | 把基本流变成高级流 | | public Bufferedwriter(Writer) | 把基本流变成高级流 | 字符缓冲流特有方法 | 字符缓冲输入流特有方法 | 说明 | | ------------------------ | -------------------------------------------- | | public string readLine() | 读取一行数据,如果没有数据可读了,会返回null | */ public class BufferedStream03 { public static void main(String[] args) throws IOException { //创建对象 BufferedReader sr = new BufferedReader(new FileReader("D:\\JavaCode\\code\\codeText01\\src\\text\\IOStream\\BufferedStream\\BufferedStream03\\a.txt")); //读取数据 //细节: //readLine()方法在读取的时候,一次读一整行,遇到回车换行结束,但是他不会把回车换行读到内存当中 String line; while ((line = sr.readLine()) != null) { System.out.println(line); } //释放资源 sr.close(); } }
- 输出结果
- a.txt
- 输出程序
- a.txt
4.3.2 newline()
方法示例
- 代码示例
package text.IOStream.BufferedStream.BufferedStream04; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; /*字符缓冲流 字符缓冲流的构造方法 | 方法名称 | 说明 | | ----------------------------- | ------------------ | | public BufferedReader(Reader) | 把基本流变成高级流 | | public Bufferedwriter(Writer) | 把基本流变成高级流 | 字符缓冲流特有方法 | 字符缓冲输出流特有方法 | 说明 | | ---------------------- | ------------ | | public void newLine() | 跨平台的换行 | */ public class BufferedStream04 { public static void main(String[] args) throws IOException { //创建对象 BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\JavaCode\\code\\codeText01\\src\\text\\IOStream\\BufferedStream\\BufferedStream04\\a.txt")); //输出数据 String str = "星空下,月色如水,\n" + "流淌着永恒的誓言,"; bw.write(str); //bw.write("\n\t");//原来代码是这样写的,只不过不同的系统,回车换行符号不一样 bw.newLine(); String str1 = "风吹过山川河流,\n" + "将我心意传达到远方。"; bw.write(str1); //释放资源 bw.close(); } }
- 输出结果
5. 字节缓冲流提高效率的原理
-
缓冲流自带长度为
8192
的缓冲区-
对于字节流而言,缓冲区为8k的字节数组
-
对于字符流而言,缓冲区为16k的字节数组(一个字符等于两个字节)
-
-
可以显著提高字节流的读写性能
-
对于字符流提升不明显,对于字符流而言关键点就是两个特有的方法
6. 注意事项
-
Flush操作:缓冲流内部会维护一个缓冲区,数据会先写入缓冲区而非立即写入目标流,因此在关闭流或确保数据已经写入目标流之前,需要调用
flush()
方法手动刷新缓冲区,以防止数据丢失。 -
关闭流:使用缓冲流时,应该在不再需要使用流时手动关闭流。可以使用 try-with-resources 结构来自动关闭流,确保资源能够及时释放。
-
性能考量:尽管缓冲流能够提高性能,但在某些情况下可能并不适用,例如在面对大文件或对实时性要求较高的情况下,过多的缓冲可能会导致延迟,需根据具体情况进行权衡。
-
线程安全性:缓冲流并非线程安全的,如果需要在多线程环境下使用,应该考虑使用同步措施来确保线程安全。
-
字符编码:在使用缓冲字符流时,需要注意字符编码的设置,尤其是在涉及跨平台或国际化的情况下,确保正确的字符编码。
-
异常处理:在使用缓冲流时,及时捕获和处理可能发生的异常,以避免程序出现意外错误。