NPOI版本:2.7.4
帮助类:
/// <summary>
/// NPOI帮助类
/// </summary>
public static class NPOIHelper
{
/// <summary>
/// 拆分合并单元格并填充数据到每个子单元格中
/// </summary>
/// <param name="sheet"></param>
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 "";
}
}
}
调用:
/// <summary>
/// 读取Excel文件并将第二行作为DataTable的表头
/// </summary>
/// <param name="filePath">Excel文件路径</param>
/// <param name="sheetIndex">工作表索引</param>
/// <returns>包含数据的DataTable</returns>
private 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;
}