当前位置: 首页 > news >正文

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

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");elsereturn 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;
}

http://www.dtcms.com/a/357753.html

相关文章:

  • vscode里面可以批量放弃更改
  • Linux驱动异步通知机制详解
  • Labview邪修01:贪吃蛇
  • 【完整源码+数据集+部署教程】控制台缺陷检测系统源码和数据集:改进yolo11-repvit
  • IDEA编译报错:Error:(3, 28) java: 程序包com.alibaba.fastjson不存在
  • GPFS性能优化
  • zyplayer-doc:AI 驱动的智能知识库
  • LeetCode力扣-hot100系列(2)
  • MQTT高延迟通信优化指南
  • 解密企业数据安全:服务业加密软件的核心价值
  • POE供电是什么?
  • RAG教程5:多表示索引和ColBERT
  • 不一样的发票管理模式-发票识别+发票查验接口
  • 篮球API接口:技术如何革新体育数据体验
  • FunctionAI 图像生成:简化从灵感到 API 调用的每一步
  • Spring Boot自动装配机制的原理
  • Kafka入门指南:从安装到集群部署
  • 【数据结构与算法-Day 20】从零到一掌握二叉树:定义、性质、特殊形态与存储结构全解析
  • 最新SF授权系统源码全开源无加密v5.2版本
  • 什么是Jmeter? Jmeter工作原理是什么?
  • 平安健康平安芯医AI解析:7×24小时问诊+95%诊断准确率,人文温度短板与医生效能提升引热议
  • 【完整源码+数据集+部署教程】高速公路施工区域物体检测系统源码和数据集:改进yolo11-RepNCSPELAN
  • 手写链路追踪
  • 基于Net海洋生态环境保护系统的设计与实现(代码+数据库+LW)
  • 【面试场景题】怎么做业务领域划分
  • 互联网大厂AI大模型面试解析:从基础技术到场景应用
  • Jetson进行旋转目标检测推理实现大疆无人机飞行控制
  • Python-GEE遥感云大数据分析、可视化与Satellite Embedding应用
  • leetcode算法刷题的第二十一天
  • 阿里云服务器购买流程:四种主要购买方式图文教程详解与选择参考