
本文详解如何用 scanner 正确读取 csv 文件,涵盖路径处理、字符编码、资源管理、分隔符设置及数据解析,并指出原始代码失败的根本原因(如相对路径错误、未指定编码、未捕获 ioexception 等)。
本文详解如何用 scanner 正确读取 csv 文件,涵盖路径处理、字符编码、资源管理、分隔符设置及数据解析,并指出原始代码失败的根本原因(如相对路径错误、未指定编码、未捕获 ioexception 等)。
在 Java 中,Scanner 可用于读取 CSV 文件,但其行为高度依赖配置细节。原始代码看似简洁,却存在多个隐性缺陷,导致“无报错却无输出”——这通常不是功能失效,而是逻辑未触发或资源未正确初始化。
? 常见失败原因分析
- 路径问题:new File("ChinaAirLine.csv") 使用的是相对路径,实际运行时工作目录可能并非源码所在目录(例如 IDE 默认为项目根目录),导致 File 对象指向不存在的文件,Scanner 构造成功但 hasNextLine() 立即返回 false,循环不执行。
- 编码缺失:未显式指定字符集,若 CSV 含中文或 UTF-8 BOM,系统默认编码(如 GBK)可能导致乱码或解析中断。
- 异常吞没:throws Exception 仅向上抛出,未捕获 FileNotFoundException 或 IOException,掩盖了文件不存在等关键错误。
- 资源泄漏风险:虽调用 obj.close(),但若中途异常,close() 不会被执行;应优先使用 try-with-resources。
✅ 推荐解决方案:现代 NIO.2 + Scanner(安全、清晰、可维护)
以下为修复后的完整示例,以解析如下 CSV 内容为例:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
Air China,1988 China Eastern Airlines,1991 China Southern Airlines,1991
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Year;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class CsvReaderWithScanner {
public static void main(String[] args) {
// ✅ 使用 NIO.2 显式定义绝对或可靠相对路径(推荐从类路径加载或使用 Paths.get())
Path csvPath = Paths.get("src/main/resources/ChinaAirLine.csv"); // 调整为你的实际路径
// ✅ try-with-resources 自动关闭 Scanner,避免资源泄漏
try (Scanner scanner = new Scanner(csvPath, StandardCharsets.UTF_8)) {
scanner.useDelimiter("\n"); // ⚠️ 关键:按行切分(默认 delimiter 是空白符,非换行!)
record Airline(String name, Year founded) {} // 使用 record 简化数据建模
List<airline> airlines = new ArrayList();
// ✅ 利用 Scanner 的 Iterator 特性,forEachRemaining 更简洁安全
scanner.forEachRemaining(line -> {
String[] parts = line.trim().split(",", 2); // split(,2) 防止名称含逗号时误切
if (parts.length == 2) {
try {
Airline airline = new Airline(
parts[0].trim(),
Year.parse(parts[1].trim())
);
airlines.add(airline);
} catch (Exception e) {
System.err.println("跳过无效行: " + line + " — " + e.getMessage());
}
}
});
airlines.forEach(System.out::println);
} catch (IOException e) {
System.err.println("文件读取失败,请检查路径和权限: " + e.getMessage());
e.printStackTrace();
}
}
}</airline>
? 关键要点总结
- 路径务必验证:运行前用 System.out.println(csvPath.toAbsolutePath()) 打印绝对路径,确认文件真实存在。
- 始终指定编码:StandardCharsets.UTF_8 是 Web 和国际化场景的事实标准。
- 显式设置 useDelimiter("\n"):否则 Scanner 默认以空白符(空格、制表符等)分割,nextLine() 虽可用,但后续按字段解析时易出错。
- 增强健壮性:对 split() 结果做长度校验,对 Year.parse() 做异常捕获,避免单行错误导致整个解析中断。
- 生产环境建议:对于复杂 CSV(含引号、换行、转义),请使用专业库如 Apache Commons CSV 或 OpenCSV,它们内置 RFC 4180 兼容解析,远超 Scanner 手动处理能力。
遵循以上实践,即可稳定、高效地用 Scanner 解析简单 CSV 场景,同时为后续升级至专业 CSV 库打下清晰基础。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










