处理大CSV文件时Scanner抛出NoSuchElementException异常求助
问题分析与解决方案
错误根源
java.util.NoSuchElementException: No line found 本质是某一行的CSV字段数量不足8个,导致rowScanner.next()尝试读取不存在的元素。常见触发场景:
- 第75000行附近存在空行、字段缺失的不完整行
- 字段包含逗号(比如城市名是
"Paris, France"),直接用逗号做分隔符会把单个字段拆成多个,后续读取时字段数就不够了 - 文件末尾存在空行,
lineScanner.hasNext()判断为有内容,但实际读取的是空字符串,rowScanner自然拿不到元素
修复步骤
快速定位问题行
在循环中加入行号计数和内容打印,精准定位出错的行:int lineNum = 1; lineScanner.nextLine(); // 跳过表头,行号从2开始 lineNum++; while (lineScanner.hasNext()) { String line = lineScanner.nextLine(); lineNum++; System.out.println("当前处理行号:" + lineNum + ",内容:" + line); // 新增调试代码 Scanner rowScanner = new Scanner(line); // 后续原有代码不变 }运行后就能看到报错前最后处理的行,直接去CSV文件中检查该行的格式问题。
替换CSV解析方式
Scanner完全不支持带引号的逗号字段,改用专业CSV解析库(比如OpenCSV)处理更可靠:// Maven依赖示例(需先引入) // <dependency> // <groupId>com.opencsv</groupId> // <artifactId>opencsv</artifactId> // <version>5.6</version> // </dependency> private static void FillPopulation(){ Connection con = null; try{ con = DriverManager.getConnection(DATA_BASE); CSVReader reader = new CSVReader(new FileReader(EXCEL_TO_PROCESS)); String[] nextLine; reader.readNext(); // 跳过表头 while ((nextLine = reader.readNext()) != null) { // 自动处理带引号的逗号,直接拿到每行的字段数组 if (nextLine.length != 8) { System.out.println("格式错误行:" + Arrays.toString(nextLine)); continue; // 跳过错误行,避免程序中断 } String year = nextLine[0]; String avgTemp = nextLine[1]; String minTemp = nextLine[2]; String maxTemp = nextLine[3]; String cityName = nextLine[4]; String countryName = nextLine[5]; String latitude = nextLine[6]; String longitude = nextLine[7]; // 简化空值处理 avgTemp = avgTemp.isEmpty() ? "0" : avgTemp; minTemp = minTemp.isEmpty() ? "0" : minTemp; maxTemp = maxTemp.isEmpty() ? "0" : maxTemp; // 使用PreparedStatement避免SQL注入,同时提升执行效率 String query = "INSERT INTO CityTemps VALUES(?, ?, ?, ?, ?, ?, ?, ?)"; PreparedStatement pstmt = con.prepareStatement(query); pstmt.setString(1, countryName); pstmt.setString(2, cityName); pstmt.setString(3, year); pstmt.setString(4, avgTemp); pstmt.setString(5, maxTemp); pstmt.setString(6, minTemp); pstmt.setString(7, latitude); pstmt.setString(8, longitude); pstmt.executeUpdate(); } }catch(Exception e){ e.printStackTrace(); } finally { // 强制关闭资源,避免泄漏 try { if (con != null) con.close(); } catch (SQLException e) { e.printStackTrace(); } } }额外优化建议
- 不要在循环内重复创建
Statement,复用PreparedStatement能大幅提升数据库操作效率 - 必须在
finally块中关闭数据库连接和文件流,防止资源泄漏 - 空值处理可以用三元运算符简化代码逻辑
- 不要在循环内重复创建
内容的提问来源于stack exchange,提问作者HarrisonO
相关产品推荐
相关产品推荐

