Wrayの知识库 Wrayの知识库
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
  • Java章节编写规范
  • Java基础

  • Java集合

  • Java并发

  • Java IO

    • Java IO概述
    • IO基础

    • 常用IO流

    • 文件与目录操作

    • Java NIO

    • 高级主题

    • 实践与性能优化

      • try-with-resources资源管理
      • 大文件读写
      • 文本文件处理
      • IO性能优化
      • IO常见坑
        • 1. 忘记关闭流
        • 2. 处理 buffer 时忽略 len
        • 3. 用字符流处理二进制文件
        • 4. 依赖默认字符集
        • 5. 大文件一次性读入内存
        • 6. write 后以为一定落盘
        • 7. 忽略符号链接和路径穿越
        • 8. NIO 写入假设一次完成
        • 专家实践清单
        • Tips 快问快答
        • 9. 总结
    • 面试与设计题

    • IO实践速查

  • JVM

目录

IO常见坑

Java IO 的 API 并不难,难的是在真实环境中避免细节问题。下面整理一些高频坑点。

# 1. 忘记关闭流

问题:

  • 文件描述符泄漏。
  • 文件无法删除或移动。
  • Socket 连接不释放。
  • 数据没有刷新出去。

建议:

try (InputStream input = Files.newInputStream(path)) {
    // use input
}

# 2. 处理 buffer 时忽略 len

错误:

while ((len = input.read(buffer)) != -1) {
    output.write(buffer);
}

正确:

while ((len = input.read(buffer)) != -1) {
    output.write(buffer, 0, len);
}

最后一次读取通常不会填满整个 buffer。

# 3. 用字符流处理二进制文件

错误:

Reader reader = new FileReader("image.png");

字符流会进行编码解码,可能破坏二进制数据。图片、视频、压缩包必须使用字节流。

# 4. 依赖默认字符集

错误:

new String(bytes);
Files.readString(path);

建议:

new String(bytes, StandardCharsets.UTF_8);
Files.readString(path, StandardCharsets.UTF_8);

# 5. 大文件一次性读入内存

错误:

List<String> lines = Files.readAllLines(bigFile);

建议:

try (BufferedReader reader = Files.newBufferedReader(bigFile, StandardCharsets.UTF_8)) {
    String line;
    while ((line = reader.readLine()) != null) {
        process(line);
    }
}

# 6. write 后以为一定落盘

write() 写到 Java 或操作系统缓冲区,并不代表数据已经物理落盘。

关键数据要考虑:

  • flush()
  • FileChannel.force()
  • 临时文件 + 原子移动
  • 事务日志
  • 校验和

# 7. 忽略符号链接和路径穿越

处理用户上传或下载路径时,不能简单拼接:

Path target = base.resolve(userInput);

需要规范化并校验是否仍在允许目录下:

Path normalized = base.resolve(userInput).normalize();
if (!normalized.startsWith(base)) {
    throw new SecurityException("invalid path");
}

# 8. NIO 写入假设一次完成

错误:

channel.write(buffer);

正确:

while (buffer.hasRemaining()) {
    channel.write(buffer);
}

非阻塞网络场景还不能简单自旋,需要注册写事件并维护待发送缓冲。

# 专家实践清单

坑点 现象 防御方式
资源泄漏 too many open files try-with-resources
默认编码 本地正常线上乱码 显式 Charset
大文件入内存 OOM 流式处理
写半文件 文件损坏 临时文件 + 原子移动
路径穿越 任意文件读写 normalize + 根目录校验
半包半写 协议错乱 明确消息边界和写队列

排查顺序:

先看异常和日志上下文
  ▼
确认资源是否关闭
  ▼
确认编码和文件大小
  ▼
确认路径和权限
  ▼
确认网络边界和超时

# Tips 快问快答

Q:IO 代码最常见的 bug 是什么? A:资源未关闭、编码错误、大文件一次性加载和路径未校验。

Q:为什么 read 不能假设读满缓冲区? A:IO 每次返回的字节数取决于底层可用数据。

Q:为什么上传文件要校验路径? A:防止 ../ 路径穿越写入非授权目录。

Q:写文件为什么要考虑原子性? A:进程崩溃或磁盘满会留下半写入文件。

Q:网络 IO 为什么必须有超时? A:对端可能长时间不响应,线程和连接会被占住。

Q:为什么不能吞掉 IOException? A:IO 失败通常意味着外部环境异常,吞掉会导致数据不一致。

Q:文件权限问题如何定位? A:看异常类型、运行用户、目录权限、挂载方式和 SELinux/容器限制。

Q:资深工程师写 IO 代码最关注什么? A:资源生命周期、数据边界、失败恢复、安全校验和可观测性。

# 9. 总结

IO 常见坑大多来自资源生命周期、边界长度、字符集、大文件、缓冲语义和安全校验。写 IO 代码时要有“外部资源不可信、外部环境不稳定、数据边界必须明确”的意识。

上次更新: 2026/06/25, 14:19:18
IO性能优化
Java IO核心面试题

← IO性能优化 Java IO核心面试题→

Copyright © 2023-2026 Wray | 鄂ICP备2024050235号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式