之前我們在使用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 }