必须 outputstreamwriter 套在 bufferedwriter 外层,因为 outputstreamwriter 是转换流,需紧贴底层 outputstream(如 fileoutputstream)以确保字符按指定编码(如 utf-8)正确转为字节;bufferedwriter 是字符缓冲流,只操作 char[],不处理编码,且其类型 writer 无法作为 outputstreamwriter 的构造参数,否则编译失败。

为什么必须 OutputStreamWriter 套在 BufferedWriter 外层?
因为 OutputStreamWriter 是转换流,负责把字符按指定编码转成字节;BufferedWriter 是缓冲流,负责把字符暂存在内存里批量写入。两者职责不同、层级不同:
- OutputStreamWriter 必须紧贴底层字节流(如 FileOutputStream),才能确保每个字符都按你指定的编码(如 UTF-8)正确转为字节序列;
- BufferedWriter 只处理字符,不关心编码——它内部操作的是 char[],写入的是字符,不是字节;
- 如果反过来把 BufferedWriter 套在 OutputStreamWriter 外面(即
new BufferedWriter(new OutputStreamWriter(...))),逻辑上可行,但实际是冗余且易出错的:BufferedWriter 会缓存字符,再交给 OutputStreamWriter 转码,这没问题; - 但如果写成
new OutputStreamWriter(new BufferedWriter(...)),就完全错误——OutputStreamWriter 需要一个 OutputStream,而 BufferedWriter 是 Writer(字符流),类型不匹配,编译直接失败。
正确的嵌套结构与数据流向
标准推荐写法是:
FileOutputStream fos = new FileOutputStream("out.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8"); // 编码在此确定
BufferedWriter bw = new BufferedWriter(osw); // 缓冲字符写入
数据从上到下流动:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 你调用
bw.write("你好")→ 字符串进入 BufferedWriter 的字符缓冲区(char[]); - 调用
bw.flush()或缓冲区满时 → BufferedWriter 把一批 char 推给 OutputStreamWriter; - OutputStreamWriter 拿到这些字符,用构造时指定的 "UTF-8" 编码,逐个转成字节序列;
- 生成的字节最终交给 FileOutputStream,写入磁盘。
编码只由 OutputStreamWriter 决定,BufferedWriter 不参与
BufferedWriter 自身没有编码参数,也不做任何编码处理。它的作用只是提升字符写入效率,比如提供 newLine()、支持大文本分块写入等。如果你改用 new OutputStreamWriter(fos, "GBK"),哪怕 BufferedWriter 完全不变,最终文件编码也会变成 GBK。
- 乱码只可能发生在 OutputStreamWriter 这一层:编码参数写错、与实际需求不符、或与读取端解码方式不一致;
- BufferedWriter 的缓冲大小(默认 8192 字符)不影响编码结果,只影响写入频率和内存占用。
flush 和 close 的协同行为
调用 bw.close() 会按顺序触发:
- 先刷新 BufferedWriter 的字符缓冲区 → 所有剩余字符交给 OutputStreamWriter;
- OutputStreamWriter 再把这批字符编码成字节 → 写入底层 FileOutputStream;
- 最后关闭 FileOutputStream。
所以不需要手动对 OutputStreamWriter 单独 flush 或 close——BufferedWriter 的 close 已包含完整清理链。但要注意:如果中途只调 bw.flush(),它不会触发 OutputStreamWriter 的底层 flush,除非 OutputStreamWriter 自己也 flush(一般不需要)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










