【Java】缓冲流详解

大家好,最近一直在梳理 Java IO 相关知识点,继字节流、字符流之后,今天来和大家深入聊一聊缓冲流。在实际开发中,单纯使用基础字节流、字符流读写文件效率偏低,而缓冲流可以大幅优化 IO 性能,也是日常项目里使用频率极高的 IO 流。

一、缓冲流核心工作原理

普通文件流每读写一次数据,都会直接和磁盘进行交互,频繁的磁盘 IO、系统调用会极大拖慢程序速度。

缓冲流的设计思路很简单:在内存中开辟一块缓冲区。数据不会直接和磁盘交互,而是先存入缓冲区,等缓冲区被填满后,再一次性批量读写磁盘数据。这样大幅减少了磁盘访问次数与系统调用次数,这也是缓冲流高效的根本原因。

二、字节缓冲流

字节缓冲流分为BufferedInputStream(字节缓冲输入流)和BufferedOutputStream(字节缓冲输出流),它是对基础字节流InputStreamOutputStream的包装增强,专门用来处理字节数据(图片、视频、压缩包等任意类型文件)。

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. 原码:首位为符号位,其余位为数值本身;
  2. 反码:正数反码等于原码,负数符号位不变,其余位取反;
  3. 补码:正数补码等于原码,负数在反码基础上加 1。计算机存储数据统一使用补码,理解这三点就能彻底搞懂字节转换的底层逻辑。

三、字符缓冲流

字符缓冲流对应BufferedReader(字符缓冲输入流)和BufferedWriter(字符缓冲输出流),专门用来处理文本文件,同样是对基础字符流的增强。

1. 常用构造方法

  • BufferedReader(Reader in):创建字符缓冲输入流
  • BufferedWriter(Writer out):创建字符缓冲输出流

2. 特有核心方法

字符缓冲流拥有两个专属方法,也是它区别于普通字符流的亮点:

  1. String readLine()按行读取文本,读取到文件末尾时返回null,日常读取日志、配置文件超实用;
  2. 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();
        }
    }
}

四、总结

  1. 缓冲流本质是包装流,必须依赖基础字节流 / 字符流使用,核心优势是借助内存缓冲区,减少磁盘 IO 次数,提升读写效率;
  2. 分类使用:字节缓冲流处理所有类型文件(图片、视频、文档等),字符缓冲流只专注文本文件;
  3. 特性区分:字符缓冲流拥有readLine()按行读取、newLine()跨平台换行两个实用特有方法;
  4. 开发建议:日常做文件读写、文件拷贝时,优先使用缓冲流,尤其是大文件场景,性能差距会非常明显。

Java IO 体系的知识点是连贯的,前面我也整理了字节流、字符流的详解文章,大家可以搭配起来学习,一步步吃透整个 IO 框架。后续我也会继续更新 IO 相关的高级用法,欢迎一起交流学习~

Tags:

发表回复

Your email address will not be published. Required fields are marked *.

*
*