package org.example; import org.apache.poi.openxml4j.util.ZipSecureFile; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import java.io.File; import java.io.FileInputStream; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Timestamp; import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * ---------纵断面数据导入器(根据实际Excel格式修正版) */ public class IaShzhVsurfaceDataImporter2 { // 纵断面主表插入SQL private static final String INSERT_VSURFACE_SQL = "INSERT INTO SHZH_JCSJ.IA_M_VSURFACE " + "(ZECD, ADCD, CHANNEL, ADDRESS, ISCTOWN, BASEELE, BASELGTD, BASELTTD, ELETYPE, " + "METHOD, SIGNER, AUDID, STATUS, REMARK, MODITIME, ISENABLE, IMPORTYEAR, AUDBATCH, " + "CADCD, GUID, INPUTTYPE, WSCD, SURFACE_CLASSIFY, OBJECT_NAME) " + "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; // 纵断面点表插入SQL private static final String INSERT_VSPOINT_SQL = "INSERT INTO SHZH_JCSJ.IA_M_VSPOINT " + "(ZSURFACEID, TRANSECTNAME, FID, POINT, DISTANCE, DIRECTION, HDEELE, SMEELE, " + "LGTD, LTTD, MODITIME, REMARK, GUID, CHANNEL) " + "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; // 检查纵断面主表重复的SQL private static final String CHECK_VSURFACE_DUPLICATE_SQL = "SELECT COUNT(*) FROM SHZH_JCSJ.IA_M_VSURFACE WHERE ZECD = ? and SURFACE_CLASSIFY = ?"; // 检查纵断面点表重复的SQL private static final String CHECK_VSPOINT_DUPLICATE_SQL = "SELECT COUNT(*) FROM SHZH_JCSJ.IA_M_VSPOINT WHERE ZSURFACEID = ? AND FID = ?"; public static void main(String[] args) { // 测试用的固定路径 // args = new String[]{"C:\\Users\\gsiot\\Desktop\\项目资料\\山洪\\小流域\\111"}; // args = new String[]{"F:\\1111-湖工大50条成果-已通过初检-待入库"}; // args = new String[]{"F:\\3333-2024年度咸宁市8条20251017-已通过初检-待入库"}; // args = new String[]{"F:\\4444-长江科学院-黄冈28条-已通过初检-已统一表头-待入库"}; args = new String[]{"C:\\Users\\gsiot\\Desktop\\项目资料\\山洪\\小流域\\111"}; if (args.length == 0) { System.out.println("请提供湖工大9.29目录路径作为参数"); return; } String baseDir = args[0]; File baseDirectory = new File(baseDir); if (!baseDirectory.exists() || !baseDirectory.isDirectory()) { System.out.println("指定的目录不存在或不是有效目录: " + baseDir); return; } System.out.println("开始处理目录: " + baseDir); try { processAllCounties(baseDirectory); } catch (Exception e) { System.err.println("处理过程中发生错误: " + e.getMessage()); e.printStackTrace(); } } private static void processAllCounties(File baseDir) { File[] countyDirs = baseDir.listFiles(File::isDirectory); if (countyDirs == null) { System.out.println("在基础目录下未找到任何县市文件夹"); return; } int totalProcessed = 0; int totalSuccess = 0; int totalDuplicates = 0; int totalPointDuplicates = 0; System.out.println("找到 " + countyDirs.length + " 个县市文件夹"); for (File countyDir : countyDirs) { String countyName = extractCountyName(countyDir.getName()); System.out.println("\n=== 处理县市: " + countyName + " ==="); try { ProcessResult result = processCountyData(countyDir, countyName); totalProcessed += result.processed; totalDuplicates += result.duplicates; totalPointDuplicates += result.pointDuplicates; totalSuccess++; System.out.println("✓ 成功处理 " + countyName + ",导入 " + result.processed + " 条记录,跳过 " + result.duplicates + " 条重复记录,断面点跳过 " + result.pointDuplicates + " 条重复记录"); } catch (Exception e) { System.err.println("✗ 处理县市 " + countyName + " 时出错: " + e.getMessage()); } } System.out.println("\n=== 处理完成 ==="); System.out.println("成功处理县市: " + totalSuccess + " 个"); System.out.println("总导入记录: " + totalProcessed + " 条"); System.out.println("纵断面主表跳过重复记录: " + totalDuplicates + " 条"); System.out.println("纵断面点表跳过重复记录: " + totalPointDuplicates + " 条"); } private static ProcessResult processCountyData(File countyDir, String countyName) throws Exception { int totalProcessed = 0; int totalDuplicates = 0; int totalPointDuplicates = 0; // 查找小流域目录 File watershedDir = findWatershedDirectory(countyDir); if (watershedDir == null) { System.out.println("在 " + countyName + " 下未找到小流域目录"); return new ProcessResult(0, 0, 0); } System.out.println("找到小流域目录: " + watershedDir.getName()); // 查找所有水系目录 File[] sxDirs = findSxDirectories(watershedDir); if (sxDirs == null || sxDirs.length == 0) { System.out.println("在 " + watershedDir.getPath() + " 下未找到水系目录"); return new ProcessResult(0, 0, 0); } System.out.println("找到 " + sxDirs.length + " 个水系文件夹:"); for (File sxDir : sxDirs) { System.out.println(" - " + sxDir.getName()); } // 遍历处理每个水系文件夹 for (File sxDir : sxDirs) { System.out.println("\n处理水系: " + sxDir.getName()); ProcessResult result = processSxData(sxDir, countyName); totalProcessed += result.processed; totalDuplicates += result.duplicates; totalPointDuplicates += result.pointDuplicates; System.out.println("水系 " + sxDir.getName() + " 导入 " + result.processed + " 条记录,跳过 " + result.duplicates + " 条重复记录,断面点跳过 " + result.pointDuplicates + " 条重复记录"); } return new ProcessResult(totalProcessed, totalDuplicates, totalPointDuplicates); } private static ProcessResult processSxData(File sxDir, String countyName) throws Exception { int processedCount = 0; int duplicateCount = 0; int pointDuplicateCount = 0; // 按照新的目录结构查找文件 File crossSectionDir = findCrossSectionDirectory(sxDir); if (crossSectionDir == null) { System.out.println("在 " + sxDir.getPath() + " 下未找到纵断面成果表目录"); return new ProcessResult(0, 0, 0); } System.out.println("找到纵断面成果表目录: " + crossSectionDir.getPath()); // 查找所有Excel文件 File[] excelFiles = findExcelFiles(crossSectionDir); if (excelFiles == null || excelFiles.length == 0) { System.out.println("在 " + crossSectionDir.getPath() + " 下未找到纵断面Excel文件"); return new ProcessResult(0, 0, 0); } System.out.println("找到 " + excelFiles.length + " 个纵断面Excel文件:"); for (File excelFile : excelFiles) { System.out.println(" - " + excelFile.getName()); } // 提取流域编码 String watershedCode = CommonUtils.extractWatershedCode(sxDir.getName()); System.out.println("流域编码: " + watershedCode); // 处理每个Excel文件 for (File excelFile : excelFiles) { System.out.println("\n处理文件: " + excelFile.getName()); try { // 验证文件是否为有效Excel文件 if (!isValidExcelFile(excelFile)) { System.err.println("跳过无效的Excel文件: " + excelFile.getName()); continue; } ProcessResult result = readExcelAndImport(excelFile, countyName, watershedCode); processedCount += result.processed; duplicateCount += result.duplicates; pointDuplicateCount += result.pointDuplicates; System.out.println("文件 " + excelFile.getName() + " 导入 " + result.processed + " 条记录,跳过 " + result.duplicates + " 条重复记录"); } catch (Exception e) { System.err.println("处理文件 " + excelFile.getName() + " 时出错: " + e.getMessage()); if (e.getMessage().contains("valid OOXML")) { System.err.println(" 文件可能损坏或格式不正确,跳过此文件"); } // 继续处理下一个文件 } } return new ProcessResult(processedCount, duplicateCount, pointDuplicateCount); } /** * 验证文件是否为有效的Excel文件 */ private static boolean isValidExcelFile(File file) { if (!file.exists() || !file.isFile()) { return false; } // 检查文件扩展名 String fileName = file.getName().toLowerCase(); if (!fileName.endsWith(".xlsx")) { System.err.println("文件扩展名不是.xlsx: " + file.getName()); return false; } // 检查文件大小 if (file.length() == 0) { System.err.println("文件大小为0: " + file.getName()); return false; } // 尝试打开文件验证格式 try (FileInputStream fis = new FileInputStream(file)) { // 只读取文件头进行验证,不加载整个文件 byte[] header = new byte[4]; if (fis.read(header) != 4) { return false; } // Excel文件的文件头特征 if (header[0] != 0x50 || header[1] != 0x4B || header[2] != 0x03 || header[3] != 0x04) { System.err.println("文件头不符合Excel格式: " + file.getName()); return false; } return true; } catch (Exception e) { System.err.println("验证Excel文件失败: " + file.getName() + " - " + e.getMessage()); return false; } } private static ProcessResult readExcelAndImport(File excelFile, String countyName, String wscd) throws Exception { int importedCount = 0; int duplicateCount = 0; int pointDuplicateCount = 0; // 先读取所有数据到内存 List vsurfaceDataList = new ArrayList<>(); List vspointDataList = new ArrayList<>(); readExcelData(wscd, excelFile, vsurfaceDataList, vspointDataList); if (vsurfaceDataList.isEmpty()) { System.out.println("未读取到有效数据"); return new ProcessResult(0, 0, 0); } System.out.println("成功读取 " + vsurfaceDataList.size() + " 条纵断面数据,包含 " + vspointDataList.size() + " 个断面点,开始导入数据库..."); // 批量导入数据库 ProcessResult result = batchInsertData(vsurfaceDataList, vspointDataList); return result; } private static void readExcelData(String wscd, File excelFile, List vsurfaceDataList, List vspointDataList) throws Exception { // 保存原始设置 double originalRatio = ZipSecureFile.getMinInflateRatio(); try { // 临时调整安全阈值 ZipSecureFile.setMinInflateRatio(0.001); try (FileInputStream fis = new FileInputStream(excelFile); Workbook workbook = new XSSFWorkbook(fis)) { String surfaceClassify=excelFile.getName(); Pattern pattern = Pattern.compile("^[a-zA-Z0-9]+"); Matcher matcher = pattern.matcher(surfaceClassify); if(matcher.find()){ surfaceClassify=matcher.group(); }else{ System.out.println("工作表表名有问题: " + surfaceClassify); } // 遍历所有工作表 for (int sheetIndex = 0; sheetIndex < workbook.getNumberOfSheets(); sheetIndex++) { Sheet sheet = workbook.getSheetAt(sheetIndex); String sheetName = sheet.getSheetName(); // 跳过填表说明等非数据工作表 if (sheetName.contains("填表说明") || sheetName.contains("说明")) { continue; } System.out.println("处理工作表: " + sheetName); try { // 解析纵断面主表数据 Object[] vsurfaceData = parseVsurfaceData(sheet, sheetName, wscd, surfaceClassify); if (vsurfaceData != null) { vsurfaceDataList.add(vsurfaceData); System.out.println("✓ 解析纵断面主表数据成功: " + sheetName); // 解析断面点数据 List points = parseVspointData(sheet, (String) vsurfaceData[19]); vspointDataList.addAll(points); System.out.println("✓ 解析 " + points.size() + " 个断面点数据"); } } catch (Exception e) { System.err.println("解析工作表 " + sheetName + " 时出错: " + e.getMessage()); } } } } finally { // 恢复原始设置 ZipSecureFile.setMinInflateRatio(originalRatio); } } private static Object[] parseVsurfaceData(Sheet sheet, String sheetName, String wscd, String surfaceClassify) { try { Object[] data = new Object[24]; // 对应24个插入参数 int index = 0; // 根据Excel格式解析数据 // 第1行:C列-所在位置 String location = getCellValue(sheet, 0, 2); // C1单元格 // 第2行:C列-所在沟道,G列-行政区划代码 String channel = getCellValue(sheet, 1, 2); // C2单元格 String adminCode = getCellValue(sheet, 1, 6); // G2单元格 // 第3行:C列-是否跨县 String isCrossCounty = getCellValue(sheet, 2, 2); // C3单元格 // 第4行:C列-控制点纬度,G列-控制点高程 String baseLatitude = getCellValue(sheet, 3, 2); // C4单元格 - 控制点纬度 String baseElevation = getCellValue(sheet, 3, 6); // G4单元格 - 控制点高程 // 第5行:C列-高程系,G列-测量方法 String elevationType = getCellValue(sheet, 4, 2); // C5单元格 - 高程系 String method = getCellValue(sheet, 4, 6); // G5单元格 - 测量方法 // 控制点经度(在Excel中没有明确位置,设为空) String baseLongitude = null; // 1. ZECD - 纵断面编码 (工作表名) data[index++] = sheetName; // 2. ADCD - 行政区划代码 data[index++] = getSafeString(adminCode); // 3. CHANNEL - 所在沟道 data[index++] = getSafeString(channel); // 4. ADDRESS - 所在位置 data[index++] = getSafeString(location); // 5. ISCTOWN - 是否跨县 data[index++] = getSafeString(isCrossCounty); // 6. BASEELE - 控制点高程 data[index++] = getSafeString(baseElevation); // 7. BASELGTD - 控制点经度 data[index++] = getSafeString(baseLongitude); // 8. BASELTTD - 控制点纬度 data[index++] = getSafeString(baseLatitude); // 9. ELETYPE - 高程系 data[index++] = getSafeString(elevationType); // 10. METHOD - 测量方法 data[index++] = getSafeString(method); // 11. SIGNER - 填写人姓名(默认为空) data[index++] = null; // 12. AUDID - 审核批次号(默认为空) data[index++] = null; // 13. STATUS - 状态(默认1-待审核) data[index++] = "1"; // 14. REMARK - 备注 data[index++] = null; // 15. MODITIME - 时间戳 data[index++] = new Timestamp(System.currentTimeMillis()); // 16. ISENABLE - 启用状态 data[index++] = "1"; // 17. IMPORTYEAR - 导入年份 data[index++] = "2025"; // 18. AUDBATCH - 审核批次 data[index++] = "BATCH_" + System.currentTimeMillis(); // 19. CADCD - 县级编码(从行政区划代码提取) data[index++] = adminCode != null && adminCode.length() >= 6 ? adminCode.substring(0, 6)+"000000000" : ""; // 20. GUID - 唯一标识 String guid = UUID.randomUUID().toString(); data[index++] = guid; // 21. INPUTTYPE - 录入方式 data[index++] = "1"; // 22. WSCD - 流域编码 data[index++] = wscd; // 23. SURFACE_CLASSIFY - 断面分类 data[index++] = surfaceClassify; // 24. OBJECT_NAME - 对象名称(使用沟道名称) data[index++] = null; return data; } catch (Exception e) { System.err.println("解析纵断面主表数据失败: " + e.getMessage()); e.printStackTrace(); return null; } } private static List parseVspointData(Sheet sheet, String vsurfaceId) { List points = new ArrayList<>(); try { // 找到数据开始行(从第7行开始,序号列开始) int startRow = 6; // 根据Excel格式,数据从第7行开始 System.out.println("断面点数据从第 " + (startRow + 1) + " 行开始"); for (int i = startRow; i <= sheet.getLastRowNum(); i++) { Row row = sheet.getRow(i); if (row == null) continue; // 检查序号列是否为空 Cell serialCell = row.getCell(0); if (serialCell == null || isCellEmpty(serialCell)) { continue; } Object[] pointData = parseVspointRowData(row, vsurfaceId, i - startRow + 1); if (pointData != null) { points.add(pointData); } } } catch (Exception e) { System.err.println("解析断面点数据失败: " + e.getMessage()); e.printStackTrace(); } return points; } private static Object[] parseVspointRowData(Row row, String vsurfaceId, int fid) { try { Object[] data = new Object[14]; // 对应14个插入参数 int index = 0; // 1. ZSURFACEID - 纵断面主表ID data[index++] = vsurfaceId; // 2. TRANSECTNAME - 断面名称(使用测量点) String measurePoint = getCellStringValue(row.getCell(1)); data[index++] = getSafeString(measurePoint); // 3. FID - 断面序号 data[index++] = fid; // 4. POINT - 断面信息-测量点 data[index++] = getSafeString(measurePoint); // 5. DISTANCE - 断面信息-距离(m) - 第3列 data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(2))); // 6. DIRECTION - 量距方向(°) - 第4列 data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(3))); // 7. HDEELE - 断面信息-河底高程(m) - 第5列 data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(4))); // 8. SMEELE - 断面信息-水面高程(m) - 第6列 data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(5))); // 9. LGTD - 经度(°) - 第7列 data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(6))); // 10. LTTD - 纬度(°) - 第8列 data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(7))); // 11. MODITIME - 时间戳 data[index++] = new Timestamp(System.currentTimeMillis()); // 12. REMARK - 备注 data[index++] = null; // 13. GUID - 唯一标识 data[index++] = UUID.randomUUID().toString(); // 14. CHANNEL - 量距方向(°) - 使用第4列的值 data[index++] = parseDoubleWithDefault(getCellStringValue(row.getCell(3))); return data; } catch (Exception e) { System.err.println("解析断面点行数据失败: " + e.getMessage()); return null; } } private static ProcessResult batchInsertData(List vsurfaceDataList, List vspointDataList) { int importedCount = 0; int duplicateCount = 0; int pointDuplicateCount = 0; Connection conn = null; PreparedStatement vsurfacePstmt = null; PreparedStatement vspointPstmt = null; PreparedStatement checkVsurfaceDupPstmt = null; PreparedStatement checkVspointDupPstmt = null; try { conn = DatabaseUtil.getConnection(); if (conn == null) { System.err.println("无法获取数据库连接"); return new ProcessResult(0, 0, 0); } vsurfacePstmt = conn.prepareStatement(INSERT_VSURFACE_SQL); vspointPstmt = conn.prepareStatement(INSERT_VSPOINT_SQL); checkVsurfaceDupPstmt = conn.prepareStatement(CHECK_VSURFACE_DUPLICATE_SQL); checkVspointDupPstmt = conn.prepareStatement(CHECK_VSPOINT_DUPLICATE_SQL); conn.setAutoCommit(false); // 开启事务 // 处理纵断面主表数据 for (Object[] rowData : vsurfaceDataList) { try { String zecd = (String) rowData[0]; String surface_clasify = (String) rowData[22]; // 检查纵断面是否重复 checkVsurfaceDupPstmt.setString(1, zecd); checkVsurfaceDupPstmt.setString(2, surface_clasify); try (ResultSet rs = checkVsurfaceDupPstmt.executeQuery()) { if (rs.next() && rs.getInt(1) > 0) { duplicateCount++; System.out.println("跳过重复纵断面: " + zecd); continue; } } // 插入数据 - 设置所有参数 setVsurfaceParameters(vsurfacePstmt, rowData); vsurfacePstmt.executeUpdate(); importedCount++; System.out.println("✓ 插入纵断面记录: " + zecd); } catch (Exception e) { System.err.println("纵断面数据插入失败: " + e.getMessage()); e.printStackTrace(); } } // 处理纵断面点表数据 int pointImportedCount = 0; for (Object[] pointData : vspointDataList) { try { String vsurfaceId = (String) pointData[0]; Integer fid = (Integer) pointData[2]; // 检查断面点是否重复 checkVspointDupPstmt.setString(1, vsurfaceId); checkVspointDupPstmt.setInt(2, fid); try (ResultSet rs = checkVspointDupPstmt.executeQuery()) { if (rs.next() && rs.getInt(1) > 0) { pointDuplicateCount++; continue; } } // 插入数据 - 设置所有参数 setVspointParameters(vspointPstmt, pointData); vspointPstmt.addBatch(); pointImportedCount++; // 每10条执行一次批量插入 if (pointImportedCount % 10 == 0) { vspointPstmt.executeBatch(); vspointPstmt.clearBatch(); // 清空批量 System.out.println("已批量插入 " + pointImportedCount + " 条断面点记录"); } } catch (Exception e) { System.err.println("断面点数据插入失败: " + e.getMessage()); e.printStackTrace(); } } // 执行剩余的断面点批量插入 if (pointImportedCount > 0) { vspointPstmt.executeBatch(); System.out.println("最终批量插入完成,共 " + pointImportedCount + " 条断面点记录"); } conn.commit(); // 提交事务 System.out.println("事务提交成功"); } catch (Exception e) { System.err.println("批量插入数据失败: " + e.getMessage()); e.printStackTrace(); if (conn != null) { try { conn.rollback(); System.out.println("事务回滚成功"); } catch (Exception rollbackEx) { System.err.println("事务回滚失败: " + rollbackEx.getMessage()); } } } finally { // 关闭资源 closeResource(checkVspointDupPstmt); closeResource(checkVsurfaceDupPstmt); closeResource(vspointPstmt); closeResource(vsurfacePstmt); closeResource(conn); } return new ProcessResult(importedCount, duplicateCount, pointDuplicateCount); } // 设置纵断面主表参数 private static void setVsurfaceParameters(PreparedStatement pstmt, Object[] rowData) throws Exception { for (int i = 0; i < rowData.length; i++) { Object value = rowData[i]; if (value == null) { pstmt.setNull(i + 1, java.sql.Types.NULL); } else if (value instanceof String) { pstmt.setString(i + 1, (String) value); } else if (value instanceof Double) { pstmt.setDouble(i + 1, (Double) value); } else if (value instanceof Integer) { pstmt.setInt(i + 1, (Integer) value); } else if (value instanceof Timestamp) { pstmt.setTimestamp(i + 1, (Timestamp) value); } else { pstmt.setObject(i + 1, value); } } } // 设置纵断面点表参数 private static void setVspointParameters(PreparedStatement pstmt, Object[] pointData) throws Exception { for (int i = 0; i < pointData.length; i++) { Object value = pointData[i]; if (value == null) { pstmt.setNull(i + 1, java.sql.Types.NULL); } else if (value instanceof String) { pstmt.setString(i + 1, (String) value); } else if (value instanceof Double) { pstmt.setDouble(i + 1, (Double) value); } else if (value instanceof Integer) { pstmt.setInt(i + 1, (Integer) value); } else if (value instanceof Timestamp) { pstmt.setTimestamp(i + 1, (Timestamp) value); } else { pstmt.setObject(i + 1, value); } } } // 安全关闭资源的方法 private static void closeResource(AutoCloseable resource) { if (resource != null) { try { resource.close(); } catch (Exception e) { System.err.println("关闭资源时出错: " + e.getMessage()); } } } // 辅助方法:安全获取字符串,避免null private static String getSafeString(String value) { return value != null ? value : ""; } // 辅助方法:解析Double,提供默认值 private static Double parseDoubleWithDefault(String value) { if (value != null && !value.trim().isEmpty()) { try { return Double.parseDouble(value.trim()); } catch (NumberFormatException e) { return 0.0; } } return 0.0; } // 辅助方法 private static class ProcessResult { int processed; int duplicates; int pointDuplicates; ProcessResult(int processed, int duplicates, int pointDuplicates) { this.processed = processed; this.duplicates = duplicates; this.pointDuplicates = pointDuplicates; } } // 目录查找方法(保持不变) private static File findWatershedDirectory(File countyDir) { File[] subDirs = countyDir.listFiles(File::isDirectory); if (subDirs != null) { for (File subDir : subDirs) { if (subDir.getName().contains("小流域")) { return subDir; } } if (subDirs.length > 0) return subDirs[0]; } return null; } private static File[] findSxDirectories(File watershedDir) { File[] subDirs = watershedDir.listFiles(File::isDirectory); if (subDirs != null) { List sxDirs = new ArrayList<>(); for (File subDir : subDirs) { if (subDir.getName().contains("水系") || subDir.getName().matches("^HBWFF.*")) { sxDirs.add(subDir); } } return sxDirs.toArray(new File[0]); } return null; } private static File findCrossSectionDirectory(File sxDir) { // 按照新目录结构:水系目录 > 电子数据 > 测量数据 > 防治对象断面成果 > 纵断面成果表 File electronicDataDir = findSubDirectory(sxDir, "电子数据"); if (electronicDataDir == null) { System.out.println("在 " + sxDir.getPath() + " 下未找到电子数据目录"); return null; } File measureDataDir = findSubDirectory(electronicDataDir, "测量数据"); if (measureDataDir == null) { System.out.println("在 " + electronicDataDir.getPath() + " 下未找到测量数据目录"); return null; } File sectionResultDir = findSubDirectory(measureDataDir, "防治对象断面成果"); if (sectionResultDir == null) { System.out.println("在 " + measureDataDir.getPath() + " 下未找到防治对象断面成果目录"); return null; } File crossSectionDir = findSubDirectory(sectionResultDir, "纵断面成果表"); if (crossSectionDir == null) { System.out.println("在 " + sectionResultDir.getPath() + " 下未找到纵断面成果表目录"); return null; } return crossSectionDir; } private static File findSubDirectory(File parentDir, String dirName) { File[] subDirs = parentDir.listFiles(File::isDirectory); if (subDirs != null) { for (File subDir : subDirs) { if (subDir.getName().equals(dirName)) { return subDir; } } // 如果没有精确匹配,尝试包含匹配 for (File subDir : subDirs) { if (subDir.getName().contains(dirName)) { return subDir; } } } return null; } private static File[] findExcelFiles(File crossSectionDir) { File[] files = crossSectionDir.listFiles((dir, name) -> name.toLowerCase().endsWith(".xlsx")); return files != null ? files : new File[0]; } private static String extractCountyName(String dirName) { return dirName.contains("、") ? dirName.split("、")[1].trim() : dirName; } private static String getCellValue(Sheet sheet, int rowNum, int colNum) { Row row = sheet.getRow(rowNum); if (row != null) { Cell cell = row.getCell(colNum); return getCellStringValue(cell); } return null; } private static String getCellStringValue(Cell cell) { if (cell == null) return null; try { switch (cell.getCellType()) { case STRING: return cell.getStringCellValue().trim(); case NUMERIC: double num = cell.getNumericCellValue(); return (num == (long) num) ? String.valueOf((long) num) : String.valueOf(num); case BOOLEAN: return String.valueOf(cell.getBooleanCellValue()); default: return null; } } catch (Exception e) { return null; } } private static boolean isCellEmpty(Cell cell) { if (cell == null) return true; switch (cell.getCellType()) { case BLANK: return true; case STRING: return cell.getStringCellValue().trim().isEmpty(); default: return false; } } }