根本区别在于处理单位和数据语义:字节流以8位字节为单位面向二进制,字符流以16位unicode字符为单位面向文本;字节流无损处理所有文件(如图片、音频、zip),字符流自动处理编码(如utf-8),专用于文本(如txt、json),避免乱码。

字节流和字符流的根本区别在于处理单位和数据语义:字节流以 8 位字节 为单位,面向二进制;字符流以 16 位 Unicode 字符 为单位,面向文本。选哪个不看“高级感”,而看你要操作的是什么数据、是否需要编码干预。
看数据类型:二进制就用字节流,纯文本优先字符流
字节流能无损处理一切文件——图片(.png)、音频(.mp3)、压缩包(.zip)、class 文件、网络原始报文。它不做任何解释,读多少字节就是多少字节。
字符流专为文本设计,比如 .txt、.csv、.json、.xml、日志文件。它会在读写时自动按指定编码(如 UTF-8)把字节转成字符,或把字符编码成字节。
- 用
FileInputStream读一个 UTF-8 的中文文本,得到的是乱码字节序列,你得自己拼、解码,极易出错 - 用
InputStreamReader(new FileInputStream(...), StandardCharsets.UTF_8)或直接用Files.newBufferedReader(path, UTF_8),一行readLine()就拿到正确字符串
看是否可控编码:字符流必须显式指定编码才可靠
字符流底层仍是字节流,只是封装了编解码逻辑。但它的默认编码有风险:
-
FileReader和FileWriter使用系统默认编码(JDK 17 前 Windows 是 GBK,Linux/macOS 多是 UTF-8),跨平台极易乱码 - 正确做法是绕过它们,用
InputStreamReader+FileInputStream或OutputStreamWriter+FileOutputStream,并传入StandardCharsets.UTF_8 - JDK 11+ 推荐直接用
Files.lines(path, UTF_8)或Files.readString(path, UTF_8),更简洁安全
看性能与便利性:批量操作别裸用基础流
无论是字节流还是字符流,裸调 read() 单字节/单字符效率极低——每次调用都触发系统 I/O。
- 字节场景:用
BufferedInputStream/BufferedOutputStream,配合byte[8192]缓冲区复制文件 - 文本场景:用
BufferedReader/BufferedWriter,支持readLine()、newLine(),自动缓冲且换行符适配平台 - 现代开发中,
Files.copy(in, out)或Files.writeString(path, content, UTF_8)已覆盖大多数简单需求,无需手动管理流
特殊场景怎么选:混合使用才是常态
真实项目里,二者常组合出现:
- HTTP 响应体是字节流(可能含图片、PDF),但响应头中的 Content-Type 字段是文本——用字符流解析头,字节流处理体
- 读取 ZIP 包内某个 UTF-8 编码的配置文件:用
ZipInputStream(字节流)定位条目,再用InputStreamReader包装其输入流,指定 UTF-8 解析内容 - 日志框架写日志:内部用
BufferedWriter(字符流)写文本,但最终落盘仍经由FileOutputStream(字节流)完成
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











