
本文详解如何在 Java 中使用 Scanner 读取文本文件时,精准跳过以 // 或 [ 开头的注释行、节标题行及空白行,并安全解析 CSV 格式工具数据。
本文详解如何在 java 中使用 scanner 读取文本文件时,精准跳过以 `//` 或 `[` 开头的注释行、节标题行及空白行,并安全解析 csv 格式工具数据。
在开发文件导入功能时,常见需求是忽略配置类或注释型内容(如 // 注释、[Section] 标题、空行),仅处理有效数据行。原代码中 if (!lineOfText.startsWith("/") && !lineOfText.startsWith("[") || lineOfText.isEmpty()) 存在两个关键缺陷:
- 逻辑运算符优先级错误:|| 优先级低于 &&,导致条件等价于 (!A && !B) || C,而实际需要的是 !(lineOfText.isEmpty() || lineOfText.startsWith("//") || lineOfText.startsWith("["));
- 字符串匹配不严谨:startsWith("/") 会误判 //comment(应跳过)和 /path(可能为有效数据),但更常见的是跳过 // 开头的单行注释,而非单个 /。
✅ 正确做法是:显式排除空行、// 开头行、[ 开头行,并借助正则表达式提升可读性与健壮性。
以下为优化后的完整实现(含关键注释):
import java.io.File;
import java.io.FileNotFoundException;
import java.util.regex.Pattern;
import java.util.Scanner;
public void readToolData() {
Frame myFrame = new Frame();
FileDialog fileName = new FileDialog(myFrame, "Select the file to load", FileDialog.LOAD);
fileName.setDirectory("/");
fileName.setVisible(true);
// 安全检查:确保目录和文件名均非 null
if (fileName.getDirectory() != null && fileName.getFile() != null) {
String filePath = fileName.getDirectory() + fileName.getFile();
System.out.printf("Selected file: %s
", filePath);
File fileData = new File(filePath);
try (Scanner scnrFile = new Scanner(fileData)) {
// 定义需跳过的行模式:空行、以 // 开头、以 [ 开头(支持 [Section] 形式)
Pattern ptrnSkip = Pattern.compile("^\s*(?://|\[).*|\s*$");
// 定义 CSV 分隔符(逗号 + 可选空格)
Pattern ptrnDlim = Pattern.compile("\s*,\s*");
while (scnrFile.hasNextLine()) {
String lineOfText = scnrFile.nextLine().trim();
// ✅ 核心过滤逻辑:仅处理非空且不匹配跳过模式的行
if (ptrnSkip.matcher(lineOfText).find()) {
System.out.printf("Skipped (comment/section/empty): "%s"
", lineOfText);
continue;
}
System.out.printf("Processing data line: "%s"
", lineOfText);
try (Scanner scnrLine = new Scanner(lineOfText).useDelimiter(ptrnDlim)) {
// 按 CSV 字段顺序解析(假设每行 8 个字段)
String toolName = scnrLine.next();
String toolCode = scnrLine.next();
int timesBorrowed = scnrLine.nextInt();
boolean onLoan = scnrLine.nextBoolean();
int cost = scnrLine.nextInt();
int weight = scnrLine.nextInt();
boolean rechargeable = scnrLine.nextBoolean();
String power = scnrLine.next();
// 构造并存储 Tool 对象(此处仅示意)
Tool t = new Tool(toolName, toolCode, timesBorrowed, onLoan, cost, weight, rechargeable, power);
this.storeTool(t);
} catch (Exception e) {
System.err.printf("Parse error in line '%s': %s
", lineOfText, e.getMessage());
}
}
} catch (FileNotFoundException e) {
System.err.println("File not found: " + e.getMessage());
e.printStackTrace();
}
} else {
System.out.println("No file selected.");
}
}? 关键改进说明:
立即学习“Java免费学习笔记(深入)”;
-
正则过滤更精准:^\s*(?://|\[).*|\s*$ 匹配:
- ^\s*// → 行首可选空格 + //;
- ^\s*\[ → 行首可选空格 + [;
- \s*$ → 全空行(含纯空格);
- 资源自动管理:使用 try-with-resources 确保 Scanner 正确关闭;
- 异常隔离:单行解析异常不影响后续行处理;
- 健壮分隔:\s*,\s* 自动忽略字段间多余空格(如 "Makita BHP452RFWX,RD2001,12 , false")。
⚠️ 注意事项:
- 若文件含 UTF-8 编码中文,需显式指定 new Scanner(fileData, "UTF-8");
- Scanner.nextInt() 等方法不消耗换行符,但本例中每行独立扫描,无需额外 nextLine();
- 生产环境推荐使用 Apache Commons CSV 库替代手动解析,它内置引号转义、多行支持、编码自适应等特性;
- 避免在 GUI 线程(如 AWT FileDialog)中执行耗时 IO,建议移至后台线程(SwingWorker 或 ExecutorService)。
通过以上重构,代码不仅修复了原始逻辑漏洞,更具备可维护性、可测试性与工程鲁棒性——这才是工业级文件解析应有的姿态。










