Java IO

大致分为:

graph TD
    A[需要处理什么数据?] -->|二进制| B[需要缓冲?]
    A -->|文本| C[需要指定编码?]
    B -->|是| D[使用BufferedInputStream/OutputStream]
    B -->|否| E[直接使用FileInputStream/OutputStream]
    C -->|是| F[使用InputStreamReader/OutputStreamWriter]
    C -->|否| G[使用FileReader/FileWriter]
    D --> H[需要处理基本类型?]
    H -->|是| I[包装DataInputStream/OutputStream]
    H -->|否| J[需要对象序列化?]
    J -->|是| K[包装ObjectInputStream/OutputStream]
    J -->|否| L[需要压缩?]
    L -->|是| M[包装GZIPInputStream/OutputStream]

Java I/O 分类

一、字节流(处理二进制数据)

1. FileInputStream

常用 API:

深入分析:

// 示例:多种读取方式对比
try (FileInputStream fis = new FileInputStream("data.bin")) {
    // 方式1:单字节读取(效率最低)
    int singleByte;
    while ((singleByte = fis.read()) != -1) {
        // 处理每个字节...
    }
    
    // 方式2:批量读取(推荐)
    byte[] buffer = new byte[1024];
    int bytesRead;
    while ((bytesRead = fis.read(buffer)) != -1) {
        processData(buffer, bytesRead); // 处理读取到的数据
    }
    
    // 方式3:精确控制读取
    byte[] part = new byte[20];
    fis.read(part, 5, 10); // 从part[5]开始填充,最多读10字节
}

最佳实践:

2. FileOutputStream

常用 API:

深入分析:

// 示例:多种写入方式
try (FileOutputStream fos = new FileOutputStream("output.bin", true)) { // 追加模式
    // 方式1:单字节写入
    fos.write(65); // 写入'A'的ASCII码
    
    // 方式2:批量写入
    byte[] data = "Hello".getBytes(StandardCharsets.UTF_8);
    fos.write(data);
    
    // 方式3:部分写入
    byte[] fullData = new byte[100];
    // ...填充数据...
    fos.write(fullData, 10, 20); // 只写入fullData[10]到[29]
    
    // 重要:确保数据真正写入磁盘
    fos.getFD().sync(); // 强制同步到磁盘
}

最佳实践:

二、字符流(处理文本数据)

3. FileReader

常用 API:

编码问题解决方案:

// 正确指定编码的FileReader替代方案
Reader reader = new InputStreamReader(
    new FileInputStream("text.txt"), 
    StandardCharsets.UTF_8);

深入分析:

// 示例:处理大文本文件
try (Reader reader = new FileReader("large.txt")) {
    char[] buffer = new char[8192];
    int charsRead;
    StringBuilder content = new StringBuilder();
    
    while ((charsRead = reader.read(buffer)) != -1) {
        content.append(buffer, 0, charsRead);
        
        // 处理逻辑可以在这里添加
        if (content.length() > 100_000) {
            processChunk(content.toString());
            content.setLength(0); // 清空缓冲区
        }
    }
    
    // 处理剩余内容
    if (content.length() > 0) {
        processChunk(content.toString());
    }
}

4. FileWriter

常用 API:

深入分析:

// 示例:日志文件写入
try (FileWriter fw = new FileWriter("app.log", true)) { // 追加模式
    // 写入日志头
    fw.write("===== 系统启动 =====\n");
    
    // 批量写入日志项
    String[] logs = getLogEntries();
    for (String log : logs) {
        fw.write(log);
        fw.write("\n"); // 换行
        
        // 每10条刷新一次
        if (++count % 10 == 0) {
            fw.flush();
        }
    }
    
    // 写入日志尾
    fw.append("\n===== 系统关闭 =====\n");
}

三、缓冲流(提高 I/O 效率)

5. BufferedInputStream(缓冲字节输入流)

用途:为字节输入流添加缓冲功能

// 示例:高效复制文件
try (BufferedInputStream bis = new BufferedInputStream(
        new FileInputStream("large.bin"))) {
    
    byte[] buffer = new byte[8192];  // 8KB缓冲
    int bytesRead;
    while ((bytesRead = bis.read(buffer)) != -1) {
        // 处理数据...
    }
}

分析

6. BufferedOutputStream(缓冲字节输出流)

用途:缓冲字节输出

try (BufferedOutputStream bos = new BufferedOutputStream(
        new FileOutputStream("out.bin"))) {
    
    for (int i = 0; i < 1000; i++) {
        bos.write(i % 256);  // 多次小量写入会被缓冲
    }
} // 自动flush并关闭

分析

7. BufferedReader(缓冲字符输入流)

用途:高效读取文本

// 示例:逐行读取文本
try (BufferedReader br = new BufferedReader(
        new FileReader("bigtext.txt"))) {
    
    String line;
    while ((line = br.readLine()) != null) {  // 读取一行
        System.out.println(line);
    }
}

分析

8. BufferedWriter(缓冲字符输出流)

用途:高效写入文本

try (BufferedWriter bw = new BufferedWriter(
        new FileWriter("log.txt"))) {
    
    bw.write("第一行");
    bw.newLine();       // 换行(跨平台安全)
    bw.write("第二行");
} // 自动flush

分析

四、转换流(字节↔字符转换)

9. InputStreamReader

用途:将字节流转换为字符流(可指定编码)

// 示例:用指定编码读取文本
try (InputStreamReader isr = new InputStreamReader(
        new FileInputStream("data.txt"), "GBK")) {
    
    char[] buf = new char[1024];
    int len;
    while ((len = isr.read(buf)) != -1) {
        System.out.print(new String(buf, 0, len));
    }
}

分析

10. OutputStreamWriter

用途:将字符流转换为字节流

try (OutputStreamWriter osw = new OutputStreamWriter(
        new FileOutputStream("out.txt"), "UTF-8")) {
    
    osw.write("使用UTF-8编码写入");
}

五、数据流(处理基本数据类型)

11. DataInputStream

核心 API:

二进制文件解析:

// 示例:解析自定义二进制格式
try (DataInputStream dis = new DataInputStream(
        new BufferedInputStream(
            new FileInputStream("data.dat")))) {
    
    // 读取文件头
    String magic = dis.readUTF();  // 读取标识符
    int version = dis.readInt();   // 版本号
    
    // 读取记录
    while (dis.available() > 0) {
        int id = dis.readInt();
        double value = dis.readDouble();
        boolean valid = dis.readBoolean();
        
        processRecord(id, value, valid);
    }
}

12. DataOutputStream

核心 API:

二进制文件生成:

// 示例:生成自定义二进制文件
try (DataOutputStream dos = new DataOutputStream(
        new BufferedOutputStream(
            new FileOutputStream("output.dat")))) {
    
    // 写入文件头
    dos.writeUTF("DATA");  // 魔数
    dos.writeInt(2);       // 版本
    
    // 写入记录
    for (DataRecord record : records) {
        dos.writeInt(record.getId());
        dos.writeDouble(record.getValue());
        dos.writeBoolean(record.isValid());
    }
    
    System.out.println("文件大小: " + dos.size() + " 字节");
}

六、对象序列化流

13. ObjectInputStream

关键 API:

自定义序列化:

class User implements Serializable {
    private static final long serialVersionUID = 1L;
    private String username;
    private transient String password; // 不序列化
    
    // 自定义序列化逻辑
    private void writeObject(ObjectOutputStream oos) throws IOException {
        oos.defaultWriteObject();  // 默认序列化
        oos.writeObject(encrypt(password)); // 加密后序列化
    }
    
    private void readObject(ObjectInputStream ois) 
            throws IOException, ClassNotFoundException {
        ois.defaultReadObject();   // 默认反序列化
        this.password = decrypt((String)ois.readObject());
    }
    
    // 加密/解密方法省略...
}

// 使用示例
try (ObjectOutputStream oos = new ObjectOutputStream(
        new FileOutputStream("users.dat"))) {
    
    User user = new User("admin", "secret");
    oos.writeObject(user);
    oos.writeUnshared(new Date()); // 即使相同也写入新对象
}

14. ObjectOutputStream

class Person implements Serializable {
    String name;
    int age;
}

// 序列化
try (ObjectOutputStream oos = new ObjectOutputStream(
        new FileOutputStream("person.dat"))) {
    oos.writeObject(new Person("张三", 25));
}

// 反序列化
try (ObjectInputStream ois = new ObjectInputStream(
        new FileInputStream("person.dat"))) {
    Person p = (Person) ois.readObject();
}

注意事项

七、打印流

15. PrintStream

16. PrintWriter

增强 API:

高级应用:

// 示例:生成CSV文件
try (PrintWriter pw = new PrintWriter(
        new BufferedWriter(
            new FileWriter("data.csv")))) {
    
    // 写入表头
    pw.println("ID,Name,Salary,Department");
    
    // 写入数据
    for (Employee emp : employees) {
        pw.printf("%d,%s,%.2f,%s%n",  // 格式化输出
            emp.getId(),
            escapeCsv(emp.getName()),  // 处理特殊字符
            emp.getSalary(),
            emp.getDepartment());
    }
    
    if (pw.checkError()) {
        System.err.println("写入文件时出错");
    }
}

String escapeCsv(String input) {
    if (input.contains(",") || input.contains("\"")) {
        return "\"" + input.replace("\"", "\"\"") + "\"";
    }
    return input;
}

NIO 桥接类

FileChannel (通过流获取)

// 示例:高效文件复制
try (FileInputStream fis = new FileInputStream("src.bin");
     FileOutputStream fos = new FileOutputStream("dest.bin");
     FileChannel src = fis.getChannel();
     FileChannel dest = fos.getChannel()) {
    
    // 三种复制方式:
    // 1. 完全复制
    dest.transferFrom(src, 0, src.size());
    
    // 2. 手动控制
    ByteBuffer buffer = ByteBuffer.allocateDirect(8192); // 直接缓冲区
    while (src.read(buffer) != -1) {
        buffer.flip();  // 切换为读模式
        dest.write(buffer);
        buffer.clear(); // 清空缓冲区
    }
    
    // 3. 内存映射文件(超大文件)
    MappedByteBuffer map = src.map(
        FileChannel.MapMode.READ_ONLY, 0, src.size());
    dest.write(map);
}

总结:各类最佳使用场景

需求场景 推荐类 原因
二进制文件读取 BufferedInputStream + FileInputStream 缓冲提高性能
二进制文件写入 BufferedOutputStream + FileOutputStream 缓冲提高性能
文本文件读取 BufferedReader + FileReader/InputStreamReader 支持行读取和编码控制
文本文件写入 BufferedWriter + FileWriter/OutputStreamWriter 缓冲提高性能
结构化数据存储 DataInputStream/DataOutputStream 保持数据类型
对象持久化 ObjectInputStream/ObjectOutputStream 完整对象序列化
日志/文本生成 PrintWriter 方便的格式化输出
超大文件处理 FileChannel + MappedByteBuffer 内存映射高效处理