Java I/O流:数据输送的“自来水管“系统

程序世界的"输水管道"

想象你家的自来水系统:
🚰 水源(文件/网络/内存)→ 管道(流)→ 水龙头(程序)
🔄 双向控制:既能接水(输入),也能排水(输出)

Java的I/O流正是这样的"管道系统",让数据在不同设备间安全高效地流动!


一、I/O流基础概念

1. 流的本质

输入流
输出流
数据源
Java程序
目的地

2. 主要流类型对比

分类维度类型特点典型实现类
数据单位字节流8位二进制处理FileInputStream
字符流16位Unicode处理FileReader
流向输入流数据读取InputStream
输出流数据写入OutputStream
功能节点流直接连接数据源/目的地FileWriter
处理流对现有流增强功能BufferedInputStream

二、四大基础流家族

1. 字节输入流:InputStream

// 文件读取示例
try (InputStream is = new FileInputStream("test.txt")) {
    byte[] buffer = new byte[1024];
    int len;
    while ((len = is.read(buffer)) != -1) {
        System.out.write(buffer, 0, len);
    }
} // try-with-resources自动关闭

2. 字节输出流:OutputStream

// 文件写入示例
try (OutputStream os = new FileOutputStream("log.txt")) {
    String data = "Hello IO";
    os.write(data.getBytes());
} // 自动关闭

3. 字符输入流:Reader

// 文本文件读取(自动处理编码)
try (Reader reader = new FileReader("note.txt", StandardCharsets.UTF_8)) {
    char[] buffer = new char[1024];
    int len;
    while ((len = reader.read(buffer)) != -1) {
        System.out.print(new String(buffer, 0, len));
    }
}

4. 字符输出流:Writer

// 文本文件写入
try (Writer writer = new FileWriter("report.txt")) {
    writer.write("用户日志\n");
    writer.append("第二行内容");
} // 自动flush并关闭

三、性能升级:缓冲流的使用

1. 缓冲流工作原理

AppBufferedStreamRawStreamread()批量读取(如8KB)数据块返回单个字节/字符AppBufferedStreamRawStream

2. 缓冲大小性能测试

缓冲大小1GB文件复制耗时
无缓冲14.2秒
1KB3.8秒
8KB2.1秒
64KB1.9秒

3. 代码示例

// 高效文件复制
try (
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream("src.zip"));
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.zip"))
) {
    byte[] buffer = new byte[8192]; // 8KB缓冲
    int len;
    while ((len = bis.read(buffer)) != -1) {
        bos.write(buffer, 0, len);
    }
}

四、高级流:装饰器模式的应用

1. 常见装饰流

装饰流功能示例
ObjectInputStream对象序列化读取读取Java对象
DataOutputStream基本数据类型写入写int/double等
ZipOutputStreamZIP压缩生成压缩文件
PrintWriter格式化输出System.out的增强版

2. 对象序列化流

// 对象写入
try (ObjectOutputStream oos = new ObjectOutputStream(
        new FileOutputStream("user.dat"))) {
    oos.writeObject(new User("Alice", 25));
}

// 对象读取
try (ObjectInputStream ois = new ObjectInputStream(
        new FileInputStream("user.dat"))) {
    User user = (User) ois.readObject();
}

3. 组合使用示例

// 读取压缩的文本文件
try (
    InputStream fis = new FileInputStream("data.gz");
    InputStream gzis = new GZIPInputStream(fis);
    Reader reader = new InputStreamReader(gzis, "UTF-8");
    BufferedReader br = new BufferedReader(reader)
) {
    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
}

五、NIO:新一代I/O系统

1. 传统IO vs NIO

特性传统IONIO
数据单位流(Stream)块(Channel & Buffer)
传输模式阻塞非阻塞
性能较低较高
复杂度简单较复杂

2. NIO核心组件

// 文件复制示例
try (
    FileChannel src = new FileInputStream("a.txt").getChannel();
    FileChannel dest = new FileOutputStream("b.txt").getChannel()
) {
    ByteBuffer buffer = ByteBuffer.allocate(8192);
    while (src.read(buffer) != -1) {
        buffer.flip();  // 切换读写模式
        dest.write(buffer);
        buffer.clear();
    }
}

3. Channel与Buffer配合

// 高效文件复制
try (FileChannel src = FileChannel.open(Paths.get("src.mp4"));
     FileChannel dest = FileChannel.open(Paths.get("copy.mp4"), 
         StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
    ByteBuffer buffer = ByteBuffer.allocateDirect(8192);
    while (src.read(buffer) != -1) {
        buffer.flip();
        dest.write(buffer);
        buffer.clear();
    }
}

4. 内存映射文件

// 超大文件处理
try (RandomAccessFile raf = new RandomAccessFile("huge.data", "r");
     FileChannel channel = raf.getChannel()) {
    MappedByteBuffer buffer = channel.map(
        FileChannel.MapMode.READ_ONLY, 0, channel.size());
    // 直接操作内存数据...
}

六、I/O最佳实践

1. 资源关闭黄金法则

// 正确做法(try-with-resources)
try (InputStream is = new FileInputStream("file")) {
    // 使用流
} // 自动关闭

// 错误做法(可能泄露资源)
InputStream is = null;
try {
    is = new FileInputStream("file");
    // ...
} finally {
    if (is != null) is.close(); // 可能忘记
}

2. 缓冲大小选择

  • 小文件:4KB-8KB
  • 大文件:8KB-64KB
  • 网络IO:1KB-4KB

3. 字符编码统一

// 显式指定编码(避免乱码)
Reader reader = new InputStreamReader(
    new FileInputStream("text.txt"), StandardCharsets.UTF_8);

4. 异常处理模板

try {
    // I/O操作
} catch (FileNotFoundException e) {
    System.err.println("文件不存在: " + e.getMessage());
} catch (IOException e) {
    System.err.println("I/O错误: " + e.getClass().getSimpleName());
} catch (Exception e) {
    System.err.println("未知错误: " + e.getMessage());
}

七、性能优化实战

1. 多线程文件处理

ExecutorService executor = Executors.newFixedThreadPool(4);
try (BufferedReader br = Files.newBufferedReader(Paths.get("bigfile.txt"))) {
    br.lines().forEach(line -> 
        executor.submit(() -> processLine(line)));
}
executor.shutdown();

2. 零拷贝技术示例

// 文件间高效传输
try (FileChannel src = FileChannel.open(Paths.get("src.iso"));
     FileChannel dest = FileChannel.open(Paths.get("copy.iso"), 
         StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
    src.transferTo(0, src.size(), dest);
}

八、常见问题解决方案

1. 大文件读取内存溢出

// 分块读取解决方案
try (RandomAccessFile raf = new RandomAccessFile("huge.log", "r")) {
    byte[] buffer = new byte[8192];
    for (long pos = 0; pos < raf.length(); pos += buffer.length) {
        raf.seek(pos);
        int read = raf.read(buffer);
        // 处理当前块...
    }
}

2. 文件复制性能对比

方法1GB文件耗时
基本字节流12.8s
缓冲流(8KB)2.3s
NIO传输1.7s
Files.copy()1.5s

3. 网络IO超时设置

Socket socket = new Socket();
socket.connect(new InetSocketAddress("example.com", 80), 3000); // 3秒超时
socket.setSoTimeout(5000); // 读写超时5秒

结语:掌握数据流动的艺术

🔧 I/O操作黄金法则

  1. 始终关闭资源(用try-with-resources)
  2. 合理使用缓冲(性能提升明显)
  3. 统一字符编码(避免乱码)
  4. 根据场景选技术(传统IO/NIO/Java7+的Files)

💡 记住这个口诀:

数据流动像水流,字节字符分清楚;
缓冲装饰效率高,资源关闭不能漏;
NIO性能虽然好,场景合适最重要;
编码统一记心头,乱码问题不再愁!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农技术栈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值