之前我们在使用npoi导入excel表格的时候,往往会遇见那种带有合并单元格的数据在导入的时候出现合并为空的问题,
也就是只有第一条有数据,其余均为空白。在网上翻了半天也没有找到合适的解决方案,最后还是想着静下心来好好研究一番,于是...
我们先来看看通常我们的导入方式,如下图,这是我们的导入模板,带有合并单元格
下面我们来看看对应的npoi所读到的DataTable数据
你会发现,只有第一行有数据,其余我们合并的单元格为空值,那我们导入到数据库必将会出错。
于是去查看代码,发现原来的获取单元格值的时候并没有去判断单元格是否进行了合并。而正好NPOI里面正好
有cell.IsMergedCell 的属性,于是我们在检测列的单元格是否合并,并且行数大于1的时候,我们就可以获取值。
一旦检测到单元格合并,并且单元格的值为空值,则让它去取上一行的值。否则直接取单元格的值即可
1 //读取每列 2 for (int j = 0; j < row.Cells.Count; j++) 3 { 4 ICell cell = row.GetCell(j); //一个单元格 5 if (cell.IsMergedCell && r > 1) //检测列的单元格是否合并 6 { 7 //dr[j] = dt.Rows[r - 2][j]; 8 var cellValue = GetCellValue(cell); 9 if (string.IsNullOrEmpty(cellValue)) 10 { 11 dr[j] = dt.Rows[r - 2][j]; 12 } 13 else 14 { 15 dr[j] = cellValue; //获取单元格的值 16 17 if (string.IsNullOrWhiteSpace(dr[j].ToString()) && j > 0) 18 { 19 dr[j] = dr[j - 1]; 20 } 21 } 22 } 23 else 24 { 25 dr[j] = GetCellValue(cell); //获取单元格的值 26 27 if (string.IsNullOrWhiteSpace(dr[j].ToString()) && j > 0) 28 { 29 dr[j] = dr[j - 1]; 30 } 31 } 32 if (dr[j].ToString() != "")//全为空则不取 33 { 34 result = true; 35 } 36 } 37 if (result == true) 38 { 39 dt.Rows.Add(dr); //把每行追加到DataTable 40 }
下面附上完整代码
1 /// <summary> 2 /// 导入Excel 带合并单元格 zhangyu 20200428 3 /// </summary> 4 /// <param name="filePath">excel文件路径</param> 5 /// <returns></returns> 6 public DataTable ExcelToDataTable(string filePath) 7 { 8 System.Web.HttpFileCollection files = System.Web.HttpContext.Current.Request.Files; 9 if (files.Count > 0 && files[0] != null) 10 { 11 if (filePath.IndexOf(".xlsx") > 0) 12 { 13 WorkBooks = new XSSFWorkbook(files[0].InputStream); 14 } 15 else 16 { 17 WorkBooks = new HSSFWorkbook(files[0].InputStream); 18 } 19 } 20 else 21 { 22 FStream = new FileStream(filePath, FileMode.Open, FileAccess.Read); 23 if (filePath.IndexOf(".xlsx") > 0) 24 { 25 WorkBooks = new XSSFWorkbook(FStream); 26 } 27 else 28 { 29 WorkBooks = new HSSFWorkbook(FStream); 30 } 31 } 32 33 DataTable dt = new DataTable(); 34 IWorkbook wk = WorkBooks; 35 //获取后缀名 36 string extension = filePath.Substring(filePath.LastIndexOf(".")).ToString().ToLower(); 37 //判断是否是excel文件 38 if (extension == ".xlsx" || extension == ".xls") 39 { 40 //获取第一个sheet 41 ISheet sheet = wk.GetSheetAt(0); 42 //获取第一行 43 IRow headrow = sheet.GetRow(0); 44 //创建列 45 for (int i = headrow.FirstCellNum; i < headrow.Cells.Count; i++) 46 { 47 ICell cell = headrow.GetCell(i); 48 dt.Columns.Add(cell.ToString()); 49 } 50 //读取每行,从第二行起 51 for (int r = 1; r <= sheet.LastRowNum; r++) 52 { 53 bool result = false; 54 DataRow dr = dt.NewRow(); 55 //获取当前行 56 IRow row = sheet.GetRow(r); 57 //读取每列 58 for (int j = 0; j < row.Cells.Count; j++) 59 { 60 ICell cell = row.GetCell(j); //一个单元格 61 if (cell.IsMergedCell && r > 1) //检测列的单元格是否合并 62 { 63 //dr[j] = dt.Rows[r - 2][j]; 64 var cellValue = GetCellValue(cell); 65 if (string.IsNullOrEmpty(cellValue)) 66 { 67 dr[j] = dt.Rows[r - 2][j]; 68 } 69 else 70 { 71 dr[j] = cellValue; //获取单元格的值 72 if (string.IsNullOrWhiteSpace(dr[j].ToString()) && j > 0) 73 { 74 dr[j] = dr[j - 1]; 75 } 76 } 77 } 78 else 79 { 80 dr[j] = GetCellValue(cell); //获取单元格的值 81 if (string.IsNullOrWhiteSpace(dr[j].ToString()) && j > 0) 82 { 83 dr[j] = dr[j - 1]; 84 } 85 } 86 if (dr[j].ToString() != "")//全为空则不取 87 { 88 result = true; 89 } 90 } 91 if (result == true) 92 { 93 dt.Rows.Add(dr); //把每行追加到DataTable 94 } 95 } 96 } 97 return dt; 98 } 99 /// <summary> 100 /// 对单元格进行判断取值 101 /// </summary> 102 /// <param name="cell"></param> 103 /// <returns></returns> 104 private static string GetCellValue(ICell cell) 105 { 106 if (cell == null) 107 return string.Empty; 108 switch (cell.CellType) 109 { 110 case CellType.Blank: //空数据类型 这里类型注意一下,不同版本NPOI大小写可能不一样,有的版本是Blank(首字母大写) 111 return string.Empty; 112 case CellType.Boolean: //bool类型 113 return cell.BooleanCellValue.ToString(); 114 case CellType.Error: 115 return cell.ErrorCellValue.ToString(); 116 case CellType.Numeric: //数字类型 117 if (HSSFDateUtil.IsCellDateFormatted(cell))//日期类型 118 { 119 return cell.DateCellValue.ToString(); 120 } 121 else //其它数字 122 { 123 return cell.NumericCellValue.ToString(); 124 } 125 case CellType.Unknown: //无法识别类型 126 default: //默认类型 127 return cell.ToString();// 128 case CellType.String: //string 类型 129 { 130 if (cell.IsMergedCell){} 131 return cell.StringCellValue; 132 } 133 134 case CellType.Formula: //带公式类型 135 try 136 { 137 HSSFFormulaEvaluator e = new HSSFFormulaEvaluator(cell.Sheet.Workbook); 138 e.EvaluateInCell(cell); 139 return cell.ToString(); 140 } 141 catch 142 { 143 return cell.NumericCellValue.ToString(); 144 } 145 } 146 }