
本文详解如何用 java 的 scanner 类安全、可靠地读取 csv 文件,涵盖路径处理、字符编码、资源管理、行/字段分割等关键要点,并提供可直接运行的示例代码与生产级建议。
本文详解如何用 java 的 scanner 类安全、可靠地读取 csv 文件,涵盖路径处理、字符编码、资源管理、行/字段分割等关键要点,并提供可直接运行的示例代码与生产级建议。
在 Java 中,仅用 Scanner 读取 CSV 文件看似简单,但实践中常因路径错误、编码不匹配、资源未释放或换行符识别异常等问题导致“静默失败”——程序无报错却无法输出内容(如原问题中 obj.hasNextLine() 始终返回 false)。根本原因在于:Scanner 默认以空白符(包括 , , , 空格)为分隔符,且对文件路径、字符集、行边界缺乏显式控制。下面将系统性地解决这些问题。
✅ 正确做法:使用 NIO.2 + 显式配置的 Scanner
推荐使用现代 Java 的 java.nio.file API 替代过时的 java.io.File,并严格指定字符编码与分隔符:
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) {
// ✅ 使用 Paths.get() 构建跨平台安全路径(避免硬编码斜杠)
Path csvPath = Paths.get("ChinaAirLine.csv"); // 或绝对路径如: "src/main/resources/ChinaAirLine.csv"
// ✅ 验证文件存在性(调试必备)
if (!java.nio.file.Files.exists(csvPath)) {
System.err.println("❌ CSV 文件不存在: " + csvPath.toAbsolutePath());
return;
}
try (Scanner scanner = new Scanner(csvPath, StandardCharsets.UTF_8)) {
// ✅ 显式设置行分隔符为 "
"(兼容 Unix/Linux/macOS);
// 若文件来自 Windows,可能含 "
",此时 useDelimiter("\R") 更鲁棒(Java 8+)
scanner.useDelimiter("\R"); // 推荐:匹配任意 Unicode 行终止符
// ✅ 定义数据结构(使用 record 提升简洁性)
record Airline(String name, Year founded) {}
List<Airline> airlines = new ArrayList<>();
// ✅ 使用 forEachRemaining + Lambda 清晰遍历每行
scanner.forEachRemaining(line -> {
if (line.trim().isEmpty()) return; // 跳过空行
String[] fields = line.split(",", 2); // 最多分割为 2 部分,防止名称含逗号干扰
if (fields.length == 2) {
try {
Airline a = new Airline(
fields[0].trim(),
Year.parse(fields[1].trim())
);
airlines.add(a);
} catch (Exception e) {
System.err.println("⚠️ 解析失败行: " + line + " → " + e.getMessage());
}
}
});
System.out.println("✅ 成功加载 " + airlines.size() + " 条航线数据:");
airlines.forEach(System.out::println);
} catch (IOException e) {
System.err.println("❌ 读取文件时发生 I/O 异常: " + e.getMessage());
}
}
}⚠️ 关键注意事项
- 路径问题:new File("ChinaAirLine.csv") 依赖当前工作目录(Working Directory),极易因 IDE 运行配置不同而找不到文件。务必改用 Paths.get(...) 并检查 Files.exists()。
- 字符编码:CSV 文件若含中文(如“中国航空”),必须显式传入 StandardCharsets.UTF_8;否则默认平台编码(如 Windows 的 GBK)会导致乱码或 InputMismatchException。
- 换行符兼容性:Windows( )、macOS( )、Linux( )换行符不同。使用 scanner.useDelimiter("\R") 可自动适配所有标准行结束符(Java 8+ 支持)。
-
CSV 复杂性限制:上述方案仅适用于简单 CSV(无嵌套引号、无换行字段、无转义)。若 CSV 含 "Air, Inc.",2005 类字段,split(",") 会错误切分。生产环境强烈推荐专业库:
- Apache Commons CSV(轻量、成熟)
- OpenCSV(API 友好)
- Jackson DataFormat CSV(适合 JSON/CVS 统一处理)
✅ 总结
Scanner 可用于快速解析格式规整的 CSV,但需主动规避路径、编码、换行符三大陷阱。始终遵循:
① 用 Paths.get() + Files.exists() 确保文件可达;
② 显式指定 StandardCharsets.UTF_8;
③ 用 useDelimiter("\R") 处理跨平台换行;
④ 使用 try-with-resources 自动关闭资源;
⑤ 对复杂 CSV,果断选用 Apache Commons CSV 等专业库——工具选对,事半功倍。


















