Loading...

【面试真题拆解】Java字节流、字符流

Java IO流的分类

Java IO流主要从两个维度分类:

分类维度 分类结果 说明
数据流向 输入流(Input) 从磁盘/网络/内存「读」数据到程序
输出流(Output) 从程序「写」数据到磁盘/网络/内存
处理单元 字节流(Byte Stream) 以「字节(byte)」为单位处理数据,是万能流
字符流(Character Stream) 以「字符(char)」为单位处理数据,专门处理文本

字节流

什么是字节流?

计算机里所有数据(图片、视频、音频、文本、PDF)本质上都是字节(0和1的组合),所以字节流是万能流,可以处理任何类型的数据。

字节流的核心类

字节流的抽象基类是 InputStream(输入流)和 OutputStream(输出流),开发中最常用的是它们的子类:

类名 作用
FileInputStream 从文件中读取字节
FileOutputStream 向文件中写入字节
BufferedInputStream 带缓冲的字节输入流,提升读性能
BufferedOutputStream 带缓冲的字节输出流,提升写性能

举个例子

字节流典型的应用——复制非文本文件(图片、视频、PDF)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class ByteStreamExample {
    public static void main(String[] args) {
        // 源文件路径(一张图片)
        String srcPath = "C:/test/photo.jpg";
        // 目标文件路径
        String destPath = "C:/test/photo_copy.jpg";

        // 用try-with-resources自动关闭流,避免内存泄漏
        try (
            // 1. 创建文件字节输入流:从源文件读字节
            FileInputStream fis = new FileInputStream(srcPath);
            // 2. 创建文件字节输出流:向目标文件写字节
            FileOutputStream fos = new FileOutputStream(destPath)
        ) {
            // 3. 定义一个字节数组作为缓冲区(一次读1024字节,即1KB,提升性能)
            byte[] buffer = new byte[1024];
            int len; // 记录每次实际读到的字节数

            // 4. 循环读写:fis.read(buffer)返回-1表示读到文件末尾
            while ((len = fis.read(buffer)) != -1) {
                // 只写实际读到的len个字节,避免最后一次写多余的空字节
                fos.write(buffer, 0, len);
            }
            System.out.println("图片复制成功!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

字符流

什么是字符流?

字符流是专门处理文本数据的流,它以【字符】为单位处理数据,内部会自动处理编码转换(比如把UTF-8编码的字节转成Java的char字符)。

为什么不用字节流处理文本?

因为中文等非ASCII字符占多个字节(比如UTF-8编码的中文占3个字节)。

如果用字节流读,可能会把一个汉字的3个字节截断,从而导致乱码

而字符流会自动识别编码,按字符读取,不会乱码。

字符流的核心类

字符流的抽象基类是 Reader(输入流)和 Writer(输出流),开发中最常用的是它们的子类:

类名 作用
FileReader 从文件中读取字符
FileWriter 向文件中写入字符
BufferedReader 带缓冲的字符输入流
BufferedWriter 带缓冲的字符输出流
InputStreamReader 转换流:字节流转字符流
OutputStreamWriter 转换流:字符流转字节流

举个例子

BufferedReaderreadLine()方法可以按行读取文本,非常方便。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

public class CharacterStreamExample {
    public static void main(String[] args) {
        String filePath = "C:/test/中文文章.txt";

        // 用转换流InputStreamReader,显式指定UTF-8编码,避免乱码
        try (
            // 1. 先创建字节输入流
            FileInputStream fis = new FileInputStream(filePath);
            // 2. 用转换流把字节流转成字符流,显式指定UTF-8编码
            InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
            // 3. 用缓冲流包装,提升性能,且有readLine()方法
            BufferedReader br = new BufferedReader(isr)
        ) {
            String line;
            int lineNum = 1;
            // readLine()返回null表示读到文件末尾
            while ((line = br.readLine()) != null) {
                System.out.println("第" + lineNum + "行:" + line);
                lineNum++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
Code Road Record