NPOI操作Excel之三解析Excel
通過(guò)前面兩篇的基礎(chǔ)學(xué)習(xí),我們對(duì)NPOI有了一定了了解,下面就開(kāi)始進(jìn)入實(shí)戰(zhàn),解析下面格式的Excel(下面只是列舉了幾個(gè)例子),并保存入庫(kù)
首先我們先分析一下,要解析這樣的Excel,需要把指標(biāo)【橘色背景和藍(lán)色背景】(作為指標(biāo)入庫(kù))、科目【棕色背景和黃色背景】(作為X軸入庫(kù))、數(shù)據(jù)【乳白色背景和白色背景】(作為Y軸入庫(kù))的數(shù)據(jù)分開(kāi)入庫(kù)。
第一張圖我們得到的指標(biāo)毫無(wú)疑問(wèn)應(yīng)該是第三行從第二列開(kāi)始到最后一列的數(shù)據(jù),而第二張圖我們得到的指標(biāo)應(yīng)該是非金融企業(yè)部門(mén)-使用、非金融企業(yè)部門(mén)-來(lái)源、金融機(jī)構(gòu)部門(mén)-使用、金融機(jī)構(gòu)部門(mén)-來(lái)源,以此類(lèi)推,我們要想取到這樣的數(shù)據(jù),首先需要把合并行的單元格填充、然后把合并列的數(shù)據(jù)合并,我們可以通過(guò)二維數(shù)組來(lái)實(shí)實(shí)現(xiàn)。
由于每個(gè)Excel的格式不一樣,指標(biāo)數(shù)據(jù)的行數(shù),列數(shù)也不一樣,所以我們要想把數(shù)據(jù)區(qū)分開(kāi)只能通過(guò)背景顏色,把三部分是數(shù)據(jù)分開(kāi)并放到三個(gè)二維數(shù)組里,然后解析入庫(kù),由于Excel的背景顏色存在不一樣,所以不能寫(xiě)死,通過(guò)觀察我們可以發(fā)現(xiàn),每個(gè)Excel都是從指標(biāo)行開(kāi)始有背景顏色到數(shù)據(jù)行開(kāi)始變背景顏色,這樣我們就可以區(qū)分開(kāi)來(lái),到這里相信聰明的你已經(jīng)知道怎么做了,下面我們就開(kāi)始實(shí)現(xiàn)吧
1、獲取Excel的擴(kuò)展名并創(chuàng)建工作簿,如果是xls創(chuàng)建HSSFWorkbook工作簿,如果是xlxs創(chuàng)建XSSFWorkbook工作簿
- public static void ReadFromExcelFile(string filePath)
- {
- IWorkbook wk = null;
- string extension = System.IO.Path.GetExtension(filePath);//GetExtension獲取Excel的擴(kuò)展名
- try
- {
- FileStream fs = File.OpenRead(filePath);
- if (extension.Equals(".xls"))
- {
- wk = new HSSFWorkbook(fs); //把xls文件中的數(shù)據(jù)寫(xiě)入wk中
- }
- else
- {
- wk = new XSSFWorkbook(fs);//把xlsx文件中的數(shù)據(jù)寫(xiě)入wk中
- }
- fs.Close();
- sheet = wk.GetSheetAt(0);//讀取當(dāng)前表數(shù)據(jù) 20 GetIndexRow();//獲取【指標(biāo)、科目、數(shù)據(jù)】的行數(shù)列數(shù)
- ReadData();//讀數(shù)據(jù)并保存到數(shù)組中
- SaveData();//解析數(shù)組數(shù)據(jù)并保存入庫(kù)
- }
- catch (Exception e)
- {
- Console.WriteLine(e.Message); //只在Debug模式下才輸出
- }
2、獲取指標(biāo)從哪行開(kāi)始
- for (int i = 0; i < sheet.LastRowNum; i++)//sheet.LastRowNum當(dāng)前表的行數(shù)
- {
- IRow row = sheet.GetRow(i); //讀取當(dāng)前行數(shù)據(jù)
- if (row != null)
- {
- if (row.GetCell(0) != null) //讀取該行的第1列數(shù)據(jù)
- {
- ICellStyle style = row.GetCell(0).CellStyle;//當(dāng)前行第一列的樣式
- row.GetCell(0).SetCellType(CellType.String);//把第一行第一列的值類(lèi)型轉(zhuǎn)換成string類(lèi)型
- short GroundColor = style.FillForegroundColor;//獲取當(dāng)前行第一列的背景色
- if (i == 0)//若或i=0說(shuō)明是第一行,沒(méi)有背景色的
- {
- Title = row.GetCell(0).StringCellValue;//獲取第一行第一列的值即標(biāo)題的值
- TitleColor = GroundColor;//第一行第一列背景色的值付給TitleColor
- continue;
- }
- else//如果不是第一行
- {
- if (GroundColor == TitleColor)
- {
- if (row.GetCell(0).StringCellValue.Contains("單位"))
- {
- IndexUnit = row.GetCell(0).StringCellValue.Replace("單位:", "").Replace("單位:", "");
- continue;
- }
- }
- else if (GroundColor != TitleColor && IndexColor == 0)//如果GroundColor不等于TitleColor說(shuō)明改行是指標(biāo)行
- {
- IndexColor = GroundColor;// 把GroundColor的值賦值給IndexColor
- IndexStart = i;//記錄改行,改行是指標(biāo)行的起始行
- break;
- }
- }
- }
- }
3、獲取指標(biāo)從哪行結(jié)束
- for (int i = IndexStart + 1; i < sheet.LastRowNum; i++)
- {
- IRow row = sheet.GetRow(i); //讀取當(dāng)前行數(shù)據(jù)
- if (row != null)
- {
- if (row.GetCell(0) != null) //讀取該行的第1列數(shù)據(jù)
- {
- ICellStyle style = row.GetCell(0).CellStyle;
- short GroundColor = style.FillForegroundColor;
- if (IndexColor != GroundColor)
- {
- LeftDataColor = GroundColor;
- IndexEnd = i - 1;
- break;
- }
- }
- }
- }
4、獲取數(shù)據(jù)從哪行開(kāi)始到哪行結(jié)束
- for (int i = IndexEnd + 1; i < sheet.LastRowNum; i++)
- {
- DataRowStart = IndexEnd + 1;//數(shù)據(jù)開(kāi)始行
- IRow row = sheet.GetRow(i); //讀取當(dāng)前行數(shù)據(jù)
- if (row != null)
- {
- if (row.GetCell(0) != null) //讀取該行的第1列數(shù)據(jù)
- {
- ICellStyle style = row.GetCell(0).CellStyle;
- short GroundColor = style.FillForegroundColor;
- if (LeftDataColor != GroundColor)
- {
- DataRowEnd = i - 1;//數(shù)據(jù)結(jié)束行
- break;
- }
- }
- }
- }
5、獲取科目【左側(cè)】的列數(shù)
- if (sheet.GetRow(IndexEnd + 1) != null)
- {
- for (int i = 0; i < sheet.GetRow(IndexEnd + 1).LastCellNum; i++)
- {
- if (sheet.GetRow(IndexEnd + 1).GetCell(i) != null)
- {
- ICellStyle style = sheet.GetRow(IndexEnd + 1).GetCell(i).CellStyle;
- short GroundColor = style.FillForegroundColor;
- sheet.GetRow(IndexEnd + 1).GetCell(i).SetCellType(CellType.String);
- if (GroundColor != LeftDataColor)
- {
- DataLeftCell = i;//科目的列數(shù)
- break;
- }
- }
- }
- }
6、把數(shù)據(jù)保存到數(shù)組中【指標(biāo)數(shù)組】
- string[,] IndexArray = new string[IndexEnd-IndexStart+1, sheet.GetRow(0).LastCellNum - DataLeftCell];//指標(biāo)
- 4 //循環(huán)指標(biāo)行
- for (int r = IndexStart; r <= IndexEnd; r++)
- {
- IRow row = sheet.GetRow(r); //讀取當(dāng)前行數(shù)據(jù)
- if (row != null)
- {
- for (int c = DataLeftCell; c <= row.LastCellNum - DataLeftCell; c++)
- {
- if (row.GetCell(c) != null)
- {
- row.GetCell(c).SetCellType(CellType.String);
- #region 判斷是否是合并單元格
- if (string.IsNullOrEmpty(row.GetCell(c).StringCellValue))
- {
- ICell cell = row.GetCell(c);
- Dimension dimension = new Dimension();
- if (IsMergedRegions.IsMergeCell(cell, out dimension))//如果是空判斷是否是合并單元格
- {
- IndexArray[r - IndexStart, c- DataLeftCell] = dimension.DataCell.StringCellValue;//如果是取合并單元格的值
- }
- else
- {
- IndexArray[r - IndexStart, c- DataLeftCell] = row.GetCell(c).StringCellValue;//否則取改單元格本身的值
- }
- }
- else
- {
- IndexArray[r - IndexStart, c- DataLeftCell] = row.GetCell(c).StringCellValue;
- }
- #endregion
- }
- }
- }
- }
7、把數(shù)據(jù)保存到數(shù)組中【科目數(shù)組】
- string[,] LeftDataArray = new string[DataRowEnd-DataRowStart+1, DataLeftCell];//科目
- for (int r = DataRowStart; r <= DataRowEnd; r++)
- {
- IRow row = sheet.GetRow(r); //讀取當(dāng)前行數(shù)據(jù)
- if (row != null)
- {
- for (int c = 0; c < DataLeftCell; c++)
- {
- if (row.GetCell(c) != null)
- {
- row.GetCell(c).SetCellType(CellType.String);
- #region 判斷是否是合并單元格
- if (string.IsNullOrEmpty(row.GetCell(c).StringCellValue))
- {
- ICell cell = row.GetCell(c);
- Dimension dimension = new Dimension();
- if (IsMergedRegions.IsMergeCell(cell, out dimension))
- {
- LeftDataArray[r - DataRowStart, c] = dimension.DataCell.StringCellValue;
- }
- else
- {
- LeftDataArray[r - DataRowStart, c] = row.GetCell(c).StringCellValue;
- }
- }
- else
- {
- LeftDataArray[r - DataRowStart, c] = row.GetCell(c).StringCellValue;
- }
- #endregion
- }
- }
- }
- }
8、把數(shù)據(jù)保存到數(shù)組中【數(shù)據(jù)數(shù)組】
- string[,] RightDataArray= new string[DataRowEnd - DataRowStart + 1, sheet.GetRow(0).LastCellNum - DataLeftCell];//數(shù)據(jù)
- for (int r = DataRowStart; r <= DataRowEnd; r++)
- {
- IRow row = sheet.GetRow(r); //讀取當(dāng)前行數(shù)據(jù)
- if (row != null)
- {
- for (int c = DataLeftCell; c < row.LastCellNum; c++)
- {
- if (row.GetCell(c) != null)
- {
- row.GetCell(c).SetCellType(CellType.String);
- RightDataArray[r - DataRowStart, c- DataLeftCell] = row.GetCell(c).StringCellValue;
- }
- }
- }
- }
9、解析數(shù)組保存數(shù)據(jù)
- private static void SaveData()
- {
- //IndexModel im = new IndexModel();
- DataModel dm = new DataModel();
- for (int ic = 0; ic < sheet.GetRow(0).LastCellNum - DataLeftCell ; ic++)//循環(huán)指標(biāo)列
- {
- dm.IndexName = null;
- dm.IndexCode = IndexCode++.ToString().PadLeft(4, '0');
- #region 獲取指標(biāo)名稱(chēng)
- for (int ir = 0; ir < IndexEnd - IndexStart + 1; ir++)
- {
- if (IndexArray[ir, ic] != null)
- {
- if (dm.IndexName == null)
- {
- dm.IndexName = IndexArray[ir, ic];
- }
- else
- {
- if (!dm.IndexName.Contains(IndexArray[ir, ic]))
- {
- dm.IndexName = dm.IndexName + "_" + IndexArray[ir, ic];//同一列字符串拼接
- }
- }
- }
- }
- #endregion
- //循環(huán)得右側(cè)數(shù)據(jù)
- for (int rr = 0; rr < DataRowEnd - DataRowStart + 1; rr++)//循環(huán)右側(cè)數(shù)據(jù)的行
- {
- #region 右側(cè)數(shù)據(jù)
- if (RightDataArray[rr, ic] != null)
- {
- dm.IndexYValue = RightDataArray[rr, ic];
- }
- #endregion
- dm.IndexXValue = null;
- //循環(huán)得左側(cè)數(shù)據(jù)
- for (int lc = 0; lc < DataLeftCell; lc++)
- {
- if (LeftDataArray[rr, lc] !=null)
- {
- if (dm.IndexXValue == null)
- {
- dm.IndexXValue = LeftDataArray[rr, lc];
- }
- else
- {
- if (!dm.IndexXValue.Contains(LeftDataArray[rr, lc]))
- {
- dm.IndexXValue = dm.IndexXValue + "_" + LeftDataArray[rr, lc];
- }
- }
- }
- }
- Console.WriteLine($"指標(biāo)名稱(chēng):{dm.IndexName} 指標(biāo)編碼:{dm.IndexCode} IndexXValue:{dm.IndexXValue} IndexYValue:{dm.IndexYValue}");
- }
- }
- }
10、上面用到的方法IsMergeCell判斷是否是合并單元格
- /// <summary>
- /// 判斷指定單元格是否為合并單元格,并且輸出該單元格的維度
- /// </summary>
- /// <param name="cell">單元格</param>
- /// <param name="dimension">單元格維度</param>
- /// <returns>返回是否為合并單元格的布爾(Boolean)值</returns>
- public static bool IsMergeCell(this ICell cell, out Dimension dimension)
- {
- return cell.Sheet.IsMergeCell(cell.RowIndex, cell.ColumnIndex, out dimension);
- }
https://www.cnblogs.com/zqyw/category/1070314.html
本文轉(zhuǎn)載自微信公眾號(hào)「CSharp編程大全」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系CSharp編程大全公眾號(hào)。























