文本文件处理
文本文件处理是业务开发中最常见的 IO 场景,包括配置文件、日志、CSV、SQL、Markdown、JSON 等。文本处理的重点是字符集、行处理、内存占用和格式边界。
# 1. 小文本文件
小文件可以直接读取为字符串:
String content = Files.readString(path, StandardCharsets.UTF_8);
写入:
Files.writeString(path, content, StandardCharsets.UTF_8);
适合配置模板、小型 SQL 文件、小 JSON 文件。
# 2. 按行读取
大多数文本处理更适合按行读取:
try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
String line;
while ((line = reader.readLine()) != null) {
handle(line);
}
}
注意 readLine() 不包含行尾换行符。
# 3. 写文本文件
try (BufferedWriter writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) {
for (String line : lines) {
writer.write(line);
writer.newLine();
}
}
如果文件是跨平台交换格式,建议明确使用 \n,避免不同系统换行差异。
# 4. 追加写入
Files.writeString(
path,
"new line\n",
StandardCharsets.UTF_8,
StandardOpenOption.CREATE,
StandardOpenOption.APPEND
);
频繁追加日志不要自己手写文件追加,应该使用成熟日志框架,如 Logback、Log4j2。
# 5. CSV 处理
简单 CSV 不能只用 split(",") 处理,因为字段可能包含逗号、引号、换行。
1,"Alice, A",20
2,"hello ""java""",30
生产环境建议使用成熟 CSV 库。自己解析 CSV 时要支持:
- 引号字段。
- 字段内逗号。
- 字段内换行。
- 转义引号。
- 空字段。
# 6. JSON 文本
小 JSON 可以整体读入后解析。
大 JSON 文件要根据格式选择流式解析,避免一次性加载巨大对象树。
例如超大数组:
[
{"id":1},
{"id":2}
]
应使用流式 JSON 解析器,而不是直接读成一个巨大 List。
# 7. BOM 问题
某些 UTF-8 文件开头可能包含 BOM。读取后第一个字符可能是 \uFEFF。
处理方式:
if (!line.isEmpty() && line.charAt(0) == '\uFEFF') {
line = line.substring(1);
}
或者使用支持 BOM 处理的工具库。
# 专家实践清单
| 问题 | 建议 | 风险 |
|---|---|---|
| 编码 | 显式 UTF-8 或业务指定编码 | 默认编码乱码 |
| 换行 | 兼容 \n、\r\n | 跨平台解析失败 |
| 大小 | 大文件按行处理 | 一次性读入 OOM |
| 格式 | CSV/JSON 用成熟库 | 手写解析边界错 |
| 异常行 | 记录行号和内容摘要 | 难以定位脏数据 |
文本处理链路:
字节文件
│ Charset 解码
▼
行 / 记录
│ 解析与校验
▼
领域对象
│
▼
业务处理
# Tips 快问快答
Q:文本文件处理最重要的参数是什么? A:字符集,其次是换行、分隔符和转义规则。
Q:CSV 可以用 split(\",\") 解析吗?
A:简单数据可以,生产复杂 CSV 不建议,因为有引号、逗号转义和换行字段。
Q:Files.readString 适合大文件吗?
A:不适合,它会把整个文件读成字符串。
Q:按行读取会保留换行符吗? A:通常不会,需要自己决定写回时的换行策略。
Q:BOM 是什么问题? A:文件开头可能带 UTF-8 BOM,解析第一列时可能出现隐藏字符。
Q:文本导入为什么要记录行号? A:脏数据排查需要快速定位具体行。
Q:复杂 JSON 日志应该怎么处理? A:用流式 JSON 解析器,避免一次性加载大文件。
Q:文本处理的专家意识是什么? A:把编码、格式边界、脏数据、内存和可恢复性都纳入设计。
# 8. 总结
文本文件处理看起来简单,真正容易出问题的是字符集、换行、格式边界和大文件内存。简单文本可以用 Files,大文本按行处理,复杂格式交给成熟解析库。