使用NPOI读取Excel需先用WorkbookFactory.Create(stream)自动识别.xls/.xlsx格式;GetRow()和GetCell()常返回null,须逐层判空;地址"A1"需用CellReference解析为0-based行列索引;中文乱码或日期显示异常时应使用DataFormatter.FormatCellValue(cell)。

用 NPOI 读取 Excel 指定单元格前,先确认文件类型
Excel 文件分 .xls(旧版二进制)和 .xlsx(新版 OOXML),NPOI 对应不同类处理:前者用 HSSFWorkbook,后者用 XSSFWorkbook。不区分直接打开会抛 Invalid header signature 错误。
- 检查扩展名,或用
FileStream读取前 8 字节判断 magic number(.xlsx开头是PK\x03\x04) - 推荐统一用
WorkbookFactory.Create(stream),它能自动识别格式,省去手动分支 - 注意
WorkbookFactory在NPOI4.0+ 才稳定支持.xls,旧版本需手动判断
GetRow() 和 GetCell() 返回 null 是常态
Excel 表格里大量“空行空列”,NPOI 不会为它们创建对象,所以 sheet.GetRow(5)?.GetCell(2) 中任意一环都可能为 null,直接调用 .StringCellValue 必崩。
- 必须逐层判空:
var row = sheet.GetRow(5); if (row == null) return; var cell = row.GetCell(2); if (cell == null) return; - 不要依赖
cell.CellType == CellType.String判断可读性——数字、日期、布尔等类型需用对应属性(NumericCellValue、BooleanCellValue) - 想安全取字符串值?用
cell.ToString()最省事,它内部已做类型适配(但精度可能丢失,比如长数字变科学计数)
读取 A1 这种地址要先转成行列索引
NPOI 所有 API 只认 0-based 行列号,不接受 "A1" 这类地址。硬写死索引容易错位,尤其表格结构变化时。
- 用
CellReference解析:var ref = new CellReference("B3"); int row = ref.Row; int col = ref.Col; - 注意
CellReference的Row和Col是 0-based,和 Excel 界面显示一致(A1→Row=0, Col=0) - 别手算
"Z10"这种列号——CellReference自动处理 A-Z/AA-AZ/BA-BZ 等进位逻辑
中文乱码或日期读成数字?检查 DataFormatter
Excel 里显示 “2024-03-15” 或 “张三”,底层可能是 double(日期序列)或 string,但格式化规则存在单元格样式中。cell.ToString() 不走样式,cell.NumericCellValue 直接吐数字。
- 用
new DataFormatter().FormatCellValue(cell),它按 Excel 实际显示格式返回字符串 -
DataFormatter依赖CellStyle,如果 Excel 文件本身没设格式(比如纯粘贴的数值),结果仍是原始值 - 对日期类型,
FormatCellValue输出受系统区域影响,如需确定格式,改用DateTime.FromOADate(cell.NumericCellValue)再格式化
真正麻烦的是合并单元格——GetCell() 对合并区内的非首单元格返回 null,得先用 sheet.GetMergedRegion(0) 拿范围,再判断目标坐标是否落在其中。这个逻辑没人封装,每次都要自己写。


















