在Java中如何使用BufferedInputStream和BufferedOutputStream优化IO

来源:个人站长作者:柬埔寨程序员头衔:程序员
导读:本期聚焦于小伙伴创作的《在Java中如何使用BufferedInputStream和BufferedOutputStream优化IO》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《在Java中如何使用BufferedInputStream和BufferedOutputStream优化IO》有用,将其分享出去将是对创作者最好的鼓励。

在Java的IO体系中,字节流是最基础的IO操作类型,但是直接使用FileInputStream和FileOutputStream进行读写时,每一次read或write调用都会触发一次底层系统的IO操作,当处理大文件或者频繁读写小数据时,这种频繁的系统调用会带来很高的性能损耗。BufferedInputStream和BufferedOutputStream作为缓冲字节流,通过在内存中维护一个缓冲区,将多次小批次的读写操作合并为少量的大批次底层IO,从而大幅降低系统调用的次数,提升IO操作的效率。

在Java中如何使用BufferedInputStream和BufferedOutputStream优化IO

缓冲流的核心工作原理

BufferedInputStream内部维护了一个字节数组作为缓冲区,默认大小为8192字节(8KB)。当调用read方法读取数据时,会优先从缓冲区中获取数据,如果缓冲区为空,才会一次性从底层输入流中读取最多等于缓冲区大小的数据填充到缓冲区,再返回数据给调用者。这样就避免了每次读取一个字节就触发一次底层IO的问题。

BufferedOutputStream的原理类似,内部同样有一个字节数组缓冲区,调用write方法写入数据时,会先将数据写入缓冲区,当缓冲区被填满,或者手动调用flush方法,或者流关闭时,才会将缓冲区中的数据一次性写入到底层输出流中,减少底层write调用的次数。

BufferedInputStream常用方法说明

BufferedInputStream继承自FilterInputStream,构造方法和常用API如下:

  • 构造方法BufferedInputStream(InputStream in) 使用默认8KB缓冲区包装传入的输入流;BufferedInputStream(InputStream in, int size) 使用指定大小的缓冲区包装输入流
  • read():从缓冲区读取一个字节,返回字节的int值,如果到达流末尾返回-1
  • read(byte[] b, int off, int len):从缓冲区读取最多len个字节到字节数组b的off位置开始的区域,返回实际读取的字节数
  • close():关闭流,同时会关闭被包装的底层输入流,不需要单独关闭底层流

BufferedOutputStream常用方法说明

BufferedOutputStream继承自FilterOutputStream,构造方法和常用API如下:

  • 构造方法BufferedOutputStream(OutputStream out) 使用默认8KB缓冲区包装传入的输出流;BufferedOutputStream(OutputStream out, int size) 使用指定大小的缓冲区包装输出流
  • write(int b):将一个字节写入缓冲区
  • write(byte[] b, int off, int len):将字节数组b中从off位置开始的len个字节写入缓冲区
  • flush():将缓冲区中未写入的数据强制写入到底层输出流
  • close():先调用flush方法,再关闭流和底层输出流

使用缓冲流实现文件复制示例

文件复制是IO操作中最常见的场景,下面使用BufferedInputStream和BufferedOutputStream实现一个高效的文件复制功能,对比不使用缓冲流的差异:

import java.io.*;

public class BufferedStreamCopyDemo {
    public static void main(String[] args) {
        // 源文件路径
        String sourcePath = "D:/test_source.txt";
        // 目标文件路径
        String targetPath = "D:/test_target.txt";
        // 调用复制方法
        copyFileWithBuffer(sourcePath, targetPath);
    }

    /**
     * 使用缓冲流复制文件
     * @param sourcePath 源文件路径
     * @param targetPath 目标文件路径
     */
    private static void copyFileWithBuffer(String sourcePath, String targetPath) {
        // 声明缓冲流对象,使用try-with-resources自动关闭流
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourcePath));
             BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(targetPath))) {
            // 定义字节数组作为临时读取容器,大小为4KB
            byte[] buffer = new byte[4096];
            int len;
            // 循环读取数据,直到到达文件末尾
            while ((len = bis.read(buffer)) != -1) {
                // 将读取到的数据写入输出缓冲流
                bos.write(buffer, 0, len);
            }
            // 手动刷新缓冲区,确保数据全部写入
            bos.flush();
            System.out.println("文件复制完成");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

上述代码中,我们使用try-with-resources语法自动管理流的生命周期,不需要手动编写close方法,避免流未关闭导致的资源泄漏问题。读取时每次从缓冲区获取最多4KB的数据,写入时先存入输出缓冲区,大幅减少了底层IO的调用次数。

缓冲流使用注意事项

缓冲区大小设置

默认的8KB缓冲区已经能满足大部分场景的需求,如果是处理大文件或者高并发的IO场景,可以适当调大缓冲区大小,比如设置为16KB、32KB,但是也不是越大越好,缓冲区过大会占用过多内存,需要根据实际场景调整。

流关闭顺序

如果手动关闭流,只需要关闭最外层的缓冲流即可,缓冲流的close方法会自动关闭被包装的底层流,不需要单独关闭FileInputStream或FileOutputStream,避免重复关闭的问题。

及时刷新输出流

如果在写入数据后没有关闭流,也没有调用flush方法,缓冲区中的数据可能不会写入到底层流中,导致数据丢失。如果是长时间运行的输出操作,建议定期调用flush方法将缓冲区数据刷入底层流。

缓冲流适用场景

缓冲流适合所有字节流的读写场景,尤其是处理大文件、频繁读写小数据的场景,对于已经自带缓冲功能的流(比如某些网络流),再包装缓冲流可能不会有明显的性能提升,反而会增加内存开销。

性能对比说明

我们可以通过简单的测试对比使用缓冲流和不使用缓冲流复制同一个100MB文件的耗时:

操作方式复制100MB文件平均耗时
不使用缓冲流,单字节读写约12000毫秒
不使用缓冲流,4KB字节数组读写约300毫秒
使用缓冲流,单字节读写约400毫秒
使用缓冲流,4KB字节数组读写约280毫秒

从测试结果可以看出,即使使用字节数组批量读写,包装缓冲流后仍然能带来一定的性能提升,而如果是单字节读写场景,缓冲流的性能提升会非常明显。

BufferedInputStreamBufferedOutputStreamJava_IO缓冲流IO_优化修改时间:2026-06-11 15:21:33

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。