> 技术文档 > 【.net core】【NPOI】读取表格信息(处理合并行表格数据)

【.net core】【NPOI】读取表格信息(处理合并行表格数据)

NPOI版本:2.7.4

帮助类:

/// /// NPOI帮助类/// public static class NPOIHelper{ ///  /// 拆分合并单元格并填充数据到每个子单元格中 ///  ///  public static void UnmergeAndFill(ISheet sheet) { // 注意:需要倒序遍历,避免拆分后索引变化 for (int i = sheet.MergedRegions.Count - 1; i >= 0; i--) { CellRangeAddress region = sheet.MergedRegions[i]; // 获取合并区域左上角单元格的值 string value = GetMergedCellValue(sheet, region.FirstRow, region.FirstColumn); // 拆分合并区域 sheet.RemoveMergedRegion(i); // 给拆分后的每个单元格填充值 for (int row = region.FirstRow; row <= region.LastRow; row++) { IRow currentRow = sheet.GetRow(row) ?? sheet.CreateRow(row); for (int col = region.FirstColumn; col <= region.LastColumn; col++) {  ICell currentCell = currentRow.GetCell(col) ?? currentRow.CreateCell(col);  currentCell.SetCellValue(value); } } } } public static string GetMergedCellValue(ISheet sheet, int rowIndex, int cellIndex) { // 遍历所有合并区域 foreach (var region in sheet.MergedRegions) { // 判断当前单元格是否在合并区域内 if (region.IsInRange(rowIndex, cellIndex)) { // 返回合并区域左上角单元格的值 IRow row = sheet.GetRow(region.FirstRow); ICell cell = row?.GetCell(region.FirstColumn); return GetCellValue(cell); } } // 非合并单元格直接返回自身值 IRow currentRow = sheet.GetRow(rowIndex); ICell currentCell = currentRow?.GetCell(cellIndex); return GetCellValue(currentCell); } // 辅助方法:获取单元格实际值(处理不同数据类型) private static string GetCellValue(ICell cell) { if (cell == null) return \"\"; switch (cell.CellType) { case CellType.String: return cell.StringCellValue; case CellType.Numeric: if (DateUtil.IsCellDateFormatted(cell))  return cell.DateCellValue == null ? \"\" : ((DateTime)cell.DateCellValue).ToString(\"yyyy-MM-dd\"); else  return cell.NumericCellValue.ToString(); case CellType.Boolean: return cell.BooleanCellValue.ToString(); default: return \"\"; } }}

调用:

/// /// 读取Excel文件并将第二行作为DataTable的表头/// /// Excel文件路径/// 工作表索引/// 包含数据的DataTableprivate DataTable ReadExcelWithSecondRowAsHeader(string filePath, int sheetIndex = 0){ DataTable dataTable = new DataTable(); using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { IWorkbook workbook; // 根据文件格式创建对应的工作簿 if (filePath.EndsWith(\".xlsx\", StringComparison.OrdinalIgnoreCase)) { workbook = new XSSFWorkbook(fileStream); } else if (filePath.EndsWith(\".xls\", StringComparison.OrdinalIgnoreCase)) { workbook = new HSSFWorkbook(fileStream); } else { throw new ArgumentException(\"不支持的文件格式\"); } // 获取指定的工作表 ISheet sheet = workbook.GetSheetAt(sheetIndex); if (sheet == null) { return dataTable; } //调用处理合并单元格数据方法 NPOIHelper.UnmergeAndFill(sheet); // 获取总行数 int rowCount = sheet.LastRowNum; if (rowCount < 1) // 至少需要有两行数据(表头行+至少一行数据) { return dataTable; } // 第二行作为表头(索引从0开始,所以是rowIndex=1) IRow headerRow = sheet.GetRow(1); if (headerRow == null) { return dataTable; } // 根据表头行创建DataTable的列 int cellCount = headerRow.LastCellNum; for (int i = 0; i < cellCount; i++) { ICell cell = headerRow.GetCell(i); string columnName = cell?.ToString() ?? $\"Column_{i}\"; // 如果列名重复,添加序号区分 if (dataTable.Columns.Contains(columnName)) { columnName = $\"{columnName}_{i}\"; } dataTable.Columns.Add(columnName); } // 从第三行开始读取数据(rowIndex从2开始) for (int i = 2; i <= rowCount; i++) { IRow dataRow = sheet.GetRow(i); if (dataRow == null) { continue; } DataRow row = dataTable.NewRow(); // 填充行数据 for (int j = 0; j < cellCount; j++) { ICell cell = dataRow.GetCell(j); if (cell != null) {  // 根据单元格类型获取对应的值  switch (cell.CellType)  { case CellType.String: row[j] = cell.StringCellValue; break; case CellType.Numeric: if (DateUtil.IsCellDateFormatted(cell)) { row[j] = cell.DateCellValue; } else { row[j] = cell.NumericCellValue; } break; case CellType.Boolean: row[j] = cell.BooleanCellValue; break; case CellType.Formula: // 处理公式单元格,获取计算结果 row[j] = cell.CachedFormulaResultType == CellType.String ? cell.StringCellValue : cell.NumericCellValue.ToString(); break; default: row[j] = cell.ToString(); break;  } } } dataTable.Rows.Add(row); } } return dataTable;}