NPOI操作Excel之三解析Excel
通過前面兩篇的基礎學習,我們對NPOI有了一定了了解,下面就開始進入實戰(zhàn),解析下面格式的Excel(下面只是列舉了幾個例子),并保存入庫
首先我們先分析一下,要解析這樣的Excel,需要把指標【橘色背景和藍色背景】(作為指標入庫)、科目【棕色背景和黃色背景】(作為X軸入庫)、數(shù)據(jù)【乳白色背景和白色背景】(作為Y軸入庫)的數(shù)據(jù)分開入庫。
第一張圖我們得到的指標毫無疑問應該是第三行從第二列開始到最后一列的數(shù)據(jù),而第二張圖我們得到的指標應該是非金融企業(yè)部門-使用、非金融企業(yè)部門-來源、金融機構部門-使用、金融機構部門-來源,以此類推,我們要想取到這樣的數(shù)據(jù),首先需要把合并行的單元格填充、然后把合并列的數(shù)據(jù)合并,我們可以通過二維數(shù)組來實實現(xiàn)。
由于每個Excel的格式不一樣,指標數(shù)據(jù)的行數(shù),列數(shù)也不一樣,所以我們要想把數(shù)據(jù)區(qū)分開只能通過背景顏色,把三部分是數(shù)據(jù)分開并放到三個二維數(shù)組里,然后解析入庫,由于Excel的背景顏色存在不一樣,所以不能寫死,通過觀察我們可以發(fā)現(xiàn),每個Excel都是從指標行開始有背景顏色到數(shù)據(jù)行開始變背景顏色,這樣我們就可以區(qū)分開來,到這里相信聰明的你已經(jīng)知道怎么做了,下面我們就開始實現(xiàn)吧
1、獲取Excel的擴展名并創(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的擴展名
- try
- {
- FileStream fs = File.OpenRead(filePath);
- if (extension.Equals(".xls"))
- {
- wk = new HSSFWorkbook(fs); //把xls文件中的數(shù)據(jù)寫入wk中
- }
- else
- {
- wk = new XSSFWorkbook(fs);//把xlsx文件中的數(shù)據(jù)寫入wk中
- }
- fs.Close();
- sheet = wk.GetSheetAt(0);//讀取當前表數(shù)據(jù) 20 GetIndexRow();//獲取【指標、科目、數(shù)據(jù)】的行數(shù)列數(shù)
- ReadData();//讀數(shù)據(jù)并保存到數(shù)組中
- SaveData();//解析數(shù)組數(shù)據(jù)并保存入庫
- }
- catch (Exception e)
- {
- Console.WriteLine(e.Message); //只在Debug模式下才輸出
- }
2、獲取指標從哪行開始
- for (int i = 0; i < sheet.LastRowNum; i++)//sheet.LastRowNum當前表的行數(shù)
- {
- IRow row = sheet.GetRow(i); //讀取當前行數(shù)據(jù)
- if (row != null)
- {
- if (row.GetCell(0) != null) //讀取該行的第1列數(shù)據(jù)
- {
- ICellStyle style = row.GetCell(0).CellStyle;//當前行第一列的樣式
- row.GetCell(0).SetCellType(CellType.String);//把第一行第一列的值類型轉換成string類型
- short GroundColor = style.FillForegroundColor;//獲取當前行第一列的背景色
- if (i == 0)//若或i=0說明是第一行,沒有背景色的
- {
- Title = row.GetCell(0).StringCellValue;//獲取第一行第一列的值即標題的值
- 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說明改行是指標行
- {
- IndexColor = GroundColor;// 把GroundColor的值賦值給IndexColor
- IndexStart = i;//記錄改行,改行是指標行的起始行
- break;
- }
- }
- }
- }
3、獲取指標從哪行結束
- for (int i = IndexStart + 1; i < sheet.LastRowNum; i++)
- {
- IRow row = sheet.GetRow(i); //讀取當前行數(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ù)從哪行開始到哪行結束
- for (int i = IndexEnd + 1; i < sheet.LastRowNum; i++)
- {
- DataRowStart = IndexEnd + 1;//數(shù)據(jù)開始行
- IRow row = sheet.GetRow(i); //讀取當前行數(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ù)結束行
- break;
- }
- }
- }
- }
5、獲取科目【左側】的列數(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ù)組中【指標數(shù)組】
- string[,] IndexArray = new string[IndexEnd-IndexStart+1, sheet.GetRow(0).LastCellNum - DataLeftCell];//指標
- 4 //循環(huán)指標行
- for (int r = IndexStart; r <= IndexEnd; r++)
- {
- IRow row = sheet.GetRow(r); //讀取當前行數(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); //讀取當前行數(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); //讀取當前行數(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)指標列
- {
- dm.IndexName = null;
- dm.IndexCode = IndexCode++.ToString().PadLeft(4, '0');
- #region 獲取指標名稱
- 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)得右側數(shù)據(jù)
- for (int rr = 0; rr < DataRowEnd - DataRowStart + 1; rr++)//循環(huán)右側數(shù)據(jù)的行
- {
- #region 右側數(shù)據(jù)
- if (RightDataArray[rr, ic] != null)
- {
- dm.IndexYValue = RightDataArray[rr, ic];
- }
- #endregion
- dm.IndexXValue = null;
- //循環(huán)得左側數(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($"指標名稱:{dm.IndexName} 指標編碼:{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
本文轉載自微信公眾號「CSharp編程大全」,可以通過以下二維碼關注。轉載本文請聯(lián)系CSharp編程大全公眾號。