【Java】缓冲流详解
大家好,最近一直在梳理 Java IO 相关知识点,继字节流、字符流之后,今天来和大家深入聊一聊缓冲流。在实际开发中,单纯使用基础字节流、字符流读写文件效率偏低,而缓冲流可以大幅优化 IO 性能,也是日常项目里使用频率极高的 IO 流。
一、缓冲流核心工作原理
普通文件流每读写一次数据,都会直接和磁盘进行交互,频繁的磁盘 IO、系统调用会极大拖慢程序速度。
缓冲流的设计思路很简单:在内存中开辟一块缓冲区。数据不会直接和磁盘交互,而是先存入缓冲区,等缓冲区被填满后,再一次性批量读写磁盘数据。这样大幅减少了磁盘访问次数与系统调用次数,这也是缓冲流高效的根本原因。
二、字节缓冲流
字节缓冲流分为BufferedInputStream(字节缓冲输入流)和BufferedOutputStream(字节缓冲输出流),它是对基础字节流InputStream、OutputStream的包装增强,专门用来处理字节数据(图片、视频、压缩包等任意类型文件)。
1. 常用构造方法
BufferedInputStream(InputStream in):接收一个基础字节输入流,创建缓冲输入流BufferedOutputStream(OutputStream out):接收一个基础字节输出流,创建缓冲输出流
2. 代码示例:使用字节缓冲流复制文件
下面演示用字节缓冲流实现文件复制,对比原生字节流,效率提升非常明显:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 字节缓冲流实现文件复制
* @author YunYang
*/
public class BufferedByteStreamDemo {
public static void main(String[] args) {
// 源文件路径、目标文件路径
String srcPath = "D:/test.jpg";
String destPath = "D:/copy_test.jpg";
try (
// 包装基础文件流,创建字节缓冲流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcPath));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destPath))
) {
// 定义字节数组,批量读取数据
byte[] buf = new byte[1024];
int len;
// 循环读取,len代表本次读取到的字节个数
while ((len = bis.read(buf)) != -1) {
bos.write(buf, 0, len);
}
// 刷新缓冲区,强制将缓冲数据写入文件
bos.flush();
System.out.println("文件复制完成!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
3. 补充知识点:byte & 0xFF
在字节流操作中,经常会看到 byte & 0xFF 这段代码,这里简单解释一下:
Java 中byte是有符号类型,取值范围 -128 ~ 127。而底层 IO 读取数据时,我们希望得到 0 ~ 255 的无符号数值。
通过 byte & 0xFF 可以将有符号 byte 转为对应的无符号 int 值,避免数据解析出错。
顺带提一下计算机底层的编码规则:
- 原码:首位为符号位,其余位为数值本身;
- 反码:正数反码等于原码,负数符号位不变,其余位取反;
- 补码:正数补码等于原码,负数在反码基础上加 1。计算机存储数据统一使用补码,理解这三点就能彻底搞懂字节转换的底层逻辑。
三、字符缓冲流
字符缓冲流对应BufferedReader(字符缓冲输入流)和BufferedWriter(字符缓冲输出流),专门用来处理文本文件,同样是对基础字符流的增强。
1. 常用构造方法
BufferedReader(Reader in):创建字符缓冲输入流BufferedWriter(Writer out):创建字符缓冲输出流
2. 特有核心方法
字符缓冲流拥有两个专属方法,也是它区别于普通字符流的亮点:
String readLine():按行读取文本,读取到文件末尾时返回null,日常读取日志、配置文件超实用;void newLine():跨平台换行,会根据当前操作系统自动适配换行符,替代手动写\n、\r\n。
3. 代码示例:字符缓冲流读写文本文件
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/**
* 字符缓冲流读写文本文件
* @author YunYang
*/
public class BufferedCharStreamDemo {
public static void main(String[] args) {
String filePath = "D:/note.txt";
String copyPath = "D:/copy_note.txt";
// 写入文本
try (BufferedWriter bw = new BufferedWriter(new FileWriter(filePath))) {
bw.write("Java IO 缓冲流学习笔记");
bw.newLine(); // 系统自动换行
bw.write("字节缓冲流处理非文本文件");
bw.newLine();
bw.write("字符缓冲流处理文本文件");
System.out.println("文本写入完成!");
} catch (IOException e) {
e.printStackTrace();
}
// 按行读取文本并复制
try (
BufferedReader br = new BufferedReader(new FileReader(filePath));
BufferedWriter bw = new BufferedWriter(new FileWriter(copyPath))
) {
String line;
// 逐行读取,读到末尾返回null
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
}
System.out.println("文本文件复制完成!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
四、总结
- 缓冲流本质是包装流,必须依赖基础字节流 / 字符流使用,核心优势是借助内存缓冲区,减少磁盘 IO 次数,提升读写效率;
- 分类使用:字节缓冲流处理所有类型文件(图片、视频、文档等),字符缓冲流只专注文本文件;
- 特性区分:字符缓冲流拥有
readLine()按行读取、newLine()跨平台换行两个实用特有方法; - 开发建议:日常做文件读写、文件拷贝时,优先使用缓冲流,尤其是大文件场景,性能差距会非常明显。
Java IO 体系的知识点是连贯的,前面我也整理了字节流、字符流的详解文章,大家可以搭配起来学习,一步步吃透整个 IO 框架。后续我也会继续更新 IO 相关的高级用法,欢迎一起交流学习~



