核心概念
在Java I/O体系中,流(Stream)是数据传输的抽象。根据处理数据单位的不同,它们被分为两大类:
-
字节流:用于处理二进制数据,以字节(8位)为基本单位。
-
字符流:用于处理文本数据,以字符(16位Unicode)为基本单位。
1. 字节流
-
核心抽象类:
InputStream和OutputStream。 -
处理单位:字节(byte,8位)。
-
用途:可以用来处理任何类型的数据,因为所有文件(图片、视频、可执行程序、文本文件等)在底层都是以字节形式存储的。
-
特点:
-
原始数据:它不关心数据的含义,只是原样读取和写入字节。
-
通用性强:万能工具,什么都能处理。
-
处理文本可能出错:如果用它来读取文本(尤其是包含多字节字符的,如中文),可能会因为编码问题导致乱码。
-
常见子类举例:
-
FileInputStream/FileOutputStream:用于读写文件。 -
ByteArrayInputStream/ByteArrayOutputStream:用于在内存中读写数据。 -
BufferedInputStream/BufferedOutputStream:提供缓冲功能,提高读写效率。
简单示例(读取一个文件的所有字节):
try (FileInputStream fis = new FileInputStream("image.jpg")) {int byteData;while ((byteData = fis.read()) != -1) {// 处理每一个字节 byteData } } catch (IOException e) {e.printStackTrace(); }
2. 字符流
-
核心抽象类:
Reader和Writer。 -
处理单位:字符(char,16位)。
-
用途:专门为处理文本数据而设计。它能自动处理字符编码(如UTF-8, GBK等),确保正确地将字节序列转换为字符,反之亦然。
-
特点:
-
高层抽象:它理解“字符”的概念,屏蔽了底层字节编码的复杂性。
-
自动编码转换:在读取时,它将字节根据指定的字符集解码成字符;在写入时,它将字符编码成字节。默认使用系统的字符编码,但可以指定。
-
处理文本更方便、安全:是处理纯文本文件的首选。
-
常见子类举例:
-
InputStreamReader/OutputStreamWriter:桥梁作用,可以将字节流转换为字符流,并指定字符集。 -
FileReader/FileWriter:用于读写文本文件(是InputStreamReader和FileInputStream的组合的便捷类)。 -
BufferedReader/BufferedWriter:提供缓冲功能,并且BufferedReader有readLine()方法,可以方便地按行读取。
简单示例(按行读取一个文本文件):
try (BufferedReader br = new BufferedReader(new FileReader("text.txt"))) {String line;while ((line = br.readLine()) != null) {// 处理每一行文本 line } } catch (IOException e) {e.printStackTrace(); }
核心区别与联系
| 特性 | 字节流 | 字符流 |
|---|---|---|
| 基本单位 | 字节(8位) | 字符(16位Unicode) |
| 处理数据类型 | 所有二进制数据(如图片、音频、视频等) | 文本数据 |
| 核心抽象类 | InputStream, OutputStream |
Reader, Writer |
| 是否处理编码 | 否,直接操作字节 | 是,依赖字符编码进行转换 |
| 性能 | 处理非文本数据效率高 | 处理文本数据效率高且安全 |
| 关系 | 底层基础 | 基于字节流构建,通过InputStreamReader/OutputStreamWriter进行转换 |
如何选择?
-
处理非文本文件(如图片、压缩包、PDF):使用字节流。
-
处理文本文件(如.txt, .java, .html):优先使用字符流,特别是
BufferedReader和BufferedWriter,因为它们能避免乱码问题,并且提供了更方便的API(如readLine)。