
本文介绍使用Java高效、安全地逐行读取CSV文件内容,并将其存储到ArrayList中,避免Scanner异常风险,同时为后续使用StringTokenizer解析交易类型(借记/贷记)提供结构化数据基础。
本文介绍使用java高效、安全地逐行读取csv文件内容,并将其存储到arraylist
在处理CSV格式的信用交易数据(如visadata.csv)时,首要任务是将每行原始文本完整、可靠地载入内存。虽然原代码尝试用Scanner.nextLine()配合异常控制循环,但依赖NullPointerException或NoSuchElementException终止读取属于反模式:前者可能掩盖真实空指针问题,后者虽合理但Scanner对空行或末尾换行符行为不稳定,易导致漏读或崩溃。
推荐采用 BufferedReader 配合 try-with-resources 的标准方式,既保证资源自动释放,又具备更高的I/O效率和健壮性。以下是完整的、生产就绪的实现:
import java.io.*;
import java.util.*;
public class CsvImporter {
/**
* 从指定路径读取CSV文件,将每一行作为字符串添加到ArrayList中
* @param filePath CSV文件路径
* @return 包含所有非空行(含空行,保留原始格式)的ArrayList<String>
* @throws IOException 若文件不存在或读取失败
*/
public static ArrayList<String> readLinesToArrayList(String filePath) throws IOException {
ArrayList<String> lines = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = reader.readLine()) != null) {
lines.add(line); // 保留原始行内容,包括空行(如有)
}
}
return lines;
}
// 示例:主方法调用
public static void main(String[] args) {
String csvPath = "visadata.csv";
try {
ArrayList<String> transactionLines = readLinesToArrayList(csvPath);
System.out.println("成功加载 " + transactionLines.size() + " 行交易数据");
// 后续可传入 getTokens() 方法进行解析
getTokens(transactionLines);
} catch (FileNotFoundException e) {
System.err.println("❌ 错误:文件未找到 — " + csvPath);
} catch (IOException e) {
System.err.println("❌ 错误:读取文件时发生IO异常 — " + e.getMessage());
}
}
// 假设的 getTokens() 方法:使用 StringTokenizer 统计交易类型
public static void getTokens(ArrayList<String> lines) {
int total = 0, debit = 0, credit = 0;
for (String line : lines) {
if (line.trim().isEmpty()) continue; // 跳过空行
total++;
// 假设CSV格式为:cardNumber,amount,type(type列值为"DEBIT"或"CREDIT")
StringTokenizer tokenizer = new StringTokenizer(line, ",");
if (tokenizer.countTokens() >= 3) {
String type = tokenizer.nextToken().trim(); // 跳过前两列,取第三列
// 注意:实际应按列索引获取(如 nextToken() 调用三次),此处仅为示意
// 更健壮做法:用 String.split(",") 并校验数组长度
if (type.equalsIgnoreCase("DEBIT")) debit++;
else if (type.equalsIgnoreCase("CREDIT")) credit++;
}
}
System.out.printf("? 总交易数:%d|借记:%d|贷记:%d%n", total, debit, credit);
}
}关键注意事项:
- ✅ 永远优先使用 BufferedReader:比 Scanner 更轻量、更可控,readLine() 返回 null 即明确表示流结束;
- ✅ 必须使用 try-with-resources:确保 BufferedReader 在任何情况下(包括异常)都能正确关闭,防止文件句柄泄漏;
- ⚠️ 避免用异常驱动流程:NoSuchElementException 不应作为正常循环终止条件;
- ⚠️ StringTokenizer 已过时:Java官方文档建议优先使用 String.split() 或 java.util.regex.Pattern,因其更灵活、支持正则与空字段处理;
- ? CSV解析需谨慎:真实CSV可能含逗号在引号内、换行符等,简单 split(",") 或 StringTokenizer 易出错;如需工业级解析,请选用 Apache Commons CSV 或 OpenCSV 库。
通过以上方式,你将获得一个干净、可扩展、符合Java最佳实践的数据加载基础,为后续的交易分析打下坚实支撑。


















