第57章

Java I/O流概述

掌握输入输出流的分类、特点和应用场景

学习目标

Java I/O流概述

Java I/O(Input/Output)流是Java中处理输入输出的核心机制。流是一种抽象概念,它代表数据的无结构化传递。按照流的方式进行输入输出,数据被当作无结构的字节序列或字符序列。

什么是I/O流?

I/O流是Java中用于处理输入输出操作的抽象概念。它提供了一种统一的方式来处理不同类型的数据源和目标,如文件、网络连接、内存等。通过流的方式,我们可以以一致的方法读取和写入数据。

I/O流的特点

I/O流的分类

按数据单位分类

字节流 vs 字符流:
// 字节流 - 处理二进制数据
FileInputStream fis = new FileInputStream("image.jpg");
FileOutputStream fos = new FileOutputStream("copy.jpg");

// 字符流 - 处理文本数据
FileReader fr = new FileReader("text.txt");
FileWriter fw = new FileWriter("output.txt");
  • 字节流:以字节(8位)为单位
  • 字符流:以字符(16位Unicode)为单位
  • 字节流适合二进制文件
  • 字符流适合文本文件

按流向分类

输入流 vs 输出流:
// 输入流 - 从数据源读取数据
InputStream input = new FileInputStream("data.txt");
Reader reader = new FileReader("text.txt");

// 输出流 - 向目标写入数据
OutputStream output = new FileOutputStream("result.txt");
Writer writer = new FileWriter("output.txt");
  • 输入流:从数据源读取数据到程序
  • 输出流:从程序写入数据到目标
  • 基类:InputStream、Reader
  • 基类:OutputStream、Writer

按角色分类

节点流 vs 处理流:
// 节点流 - 直接连接数据源
FileInputStream fileStream = new FileInputStream("data.txt");

// 处理流 - 对其他流进行包装
BufferedInputStream bufferedStream = 
    new BufferedInputStream(fileStream);
DataInputStream dataStream = 
    new DataInputStream(bufferedStream);
  • 节点流:直接连接数据源或目标
  • 处理流:对其他流进行包装
  • 节点流:FileInputStream、FileReader
  • 处理流:BufferedInputStream、DataInputStream

流的继承体系

Java I/O流采用了清晰的继承体系,所有的流类都继承自四个抽象基类。

基类 类型 常用实现类 主要用途
InputStream 字节输入流 FileInputStream, BufferedInputStream, DataInputStream 读取字节数据
OutputStream 字节输出流 FileOutputStream, BufferedOutputStream, DataOutputStream 写入字节数据
Reader 字符输入流 FileReader, BufferedReader, InputStreamReader 读取字符数据
Writer 字符输出流 FileWriter, BufferedWriter, OutputStreamWriter 写入字符数据

装饰器模式在I/O流中的应用

Java I/O流大量使用了装饰器模式,允许动态地给对象添加功能。这种设计使得流的功能可以灵活组合。

装饰器模式示例:
// 基础流(节点流)
FileInputStream fileStream = new FileInputStream("data.txt");

// 第一层装饰(添加缓冲功能)
BufferedInputStream bufferedStream = new BufferedInputStream(fileStream);

// 第二层装饰(添加数据类型读取功能)
DataInputStream dataStream = new DataInputStream(bufferedStream);

// 现在可以高效地读取各种数据类型
int number = dataStream.readInt();
double value = dataStream.readDouble();
String text = dataStream.readUTF();

装饰器模式的优势

  • 可以动态地给对象添加功能
  • 通过组合而非继承实现功能扩展
  • 符合开闭原则,易于扩展
  • 避免了类爆炸问题

完整代码示例

IOStreamDemo.java - I/O流基础演示
/**
 * Java I/O流概述示例程序
 * 演示不同类型I/O流的基本使用方法
 * 
 * @author Java学习者
 * @version 1.0
 */
public class IOStreamDemo {
    
    /**
     * 演示字节流的基本操作
     */
    public static void demonstrateByteStream() {
        try {
            // 创建字节输出流
            FileOutputStream fos = new FileOutputStream("byte_output.txt");
            
            // 写入字节数据
            String data = "Hello, Java I/O!";
            fos.write(data.getBytes());
            fos.close();
            
            // 创建字节输入流
            FileInputStream fis = new FileInputStream("byte_output.txt");
            
            // 读取字节数据
            byte[] buffer = new byte[1024];
            int bytesRead = fis.read(buffer);
            
            if (bytesRead > 0) {
                String readData = new String(buffer, 0, bytesRead);
                System.out.println("读取到的数据: " + readData);
            }
            
            fis.close();
            
        } catch (IOException e) {
            System.err.println("字节流操作异常: " + e.getMessage());
        }
    }
    
    /**
     * 演示字符流的基本操作
     */
    public static void demonstrateCharacterStream() {
        try {
            // 创建字符输出流
            FileWriter fw = new FileWriter("character_output.txt");
            
            // 写入字符数据
            fw.write("你好,Java I/O流!");
            fw.write("\n这是第二行文本。");
            fw.close();
            
            // 创建字符输入流
            BufferedReader br = new BufferedReader(
                new FileReader("character_output.txt"));
            
            // 逐行读取字符数据
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
            
            br.close();
            
        } catch (IOException e) {
            System.err.println("字符流操作异常: " + e.getMessage());
        }
    }
    
    public static void main(String[] args) {
        System.out.println("Java I/O流概述演示程序");
        System.out.println("========================");
        
        // 演示字节流
        demonstrateByteStream();
        
        // 演示字符流
        demonstrateCharacterStream();
        
        System.out.println("程序执行完成!");
    }
}
💻 查看完整代码 - 在线IDE体验

流的选择原则

如何选择合适的流类型

选择指南

// 1. 数据类型选择
// 文本数据 → 字符流
FileReader reader = new FileReader("text.txt");

// 二进制数据 → 字节流
FileInputStream input = new FileInputStream("image.jpg");

// 2. 性能优化
// 频繁读写 → 使用缓冲流
BufferedReader br = new BufferedReader(reader);

// 3. 数据类型处理
// 基本数据类型 → 数据流
DataInputStream dis = new DataInputStream(input);
  • 处理文本数据选择字符流
  • 处理二进制数据选择字节流
  • 频繁读写使用缓冲流
  • 需要类型转换使用数据流

常见误区

// 错误:用字节流处理文本(编码问题)
FileInputStream fis = new FileInputStream("chinese.txt");

// 错误:不使用缓冲流(性能低下)
for (int i = 0; i < 10000; i++) {
    fileWriter.write("data" + i);
}

// 错误:忘记关闭流(资源泄露)
FileInputStream input = new FileInputStream("file.txt");
// ... 使用流但忘记关闭
  • 用字节流处理文本可能有编码问题
  • 不使用缓冲流导致性能低下
  • 忘记关闭流造成资源泄露
  • 不处理异常导致程序不稳定

性能优化建议

I/O性能优化要点

  • 使用缓冲流:BufferedInputStream/BufferedOutputStream可以显著提高性能
  • 合理设置缓冲区大小:根据数据量调整缓冲区大小
  • 及时关闭流:使用try-with-resources语句自动关闭流
  • 选择合适的流类型:根据数据特点选择字节流或字符流
  • 避免频繁的小量读写:尽量批量处理数据

本章小结