C# 讀取 Excel(大文件)


ASP.NET下C#讀取Excel文件,有好幾種方法,我了解到的有:Microsoft.Office.Interop.Excel.dll 、 Microsoft.Jet.OLEDB 、NPOI,其中NPOI應該是用的比較多的吧,我個人來說比較傾向使用NPOI,很方便。不過今天我的一個小伙伴突然微信我,說她現在的公司需要解析一個上百兆的Excel文件,使用NPOI會有內存溢出的問題,即使根據需求將文件大小控制在最小50M以內還是不行,問我有什么辦法能解決這個問題。

這個問題雖然我沒做深入的了解,但是按照經驗來看很可能是NPOI的瓶頸,或者說是她用的這個版本NPOI版本的瓶頸。

那么這個問題怎么解決呢?上菜!

DocumentFormat.OpenXmlSDK

對,沒錯!就是他,微軟提供的一個讀取Excel的類庫

1、通過NuGet搜索 DocumentFormat.OpenXml

我下載的是第二個,至於為啥是第二個,因為小.... 而且對.NetFramework版本沒有依賴

2、解析Excel

 1         /// <summary>
 2         /// 獲取Excel指定工作表數據
 3         /// </summary>
 4         /// <param name="filePath">Excel所在路徑</param>
 5         /// <param name="sheetName">工作表名</param>
 6         /// <returns></returns>
 7         public static void GetExcelVlaue(string filePath, string sheetName)
 8         {
 9             //打開文件
10             SpreadsheetDocument document = SpreadsheetDocument.Open(filePath, false);
11             WorkbookPart workbook = document.WorkbookPart;
12             IEnumerable<Sheet> sheets = document.WorkbookPart.Workbook.Descendants<Sheet>().Where(s => s.Name == sheetName);//此處改成讀取第一個sheet頁面即可
13             if (sheets.Count() == 0)
14             {
15                 //sheet空判斷
16             }
17             WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart.GetPartById(sheets.First().Id);
18             Worksheet worksheet = worksheetPart.Worksheet;
19             IEnumerable<Row> rows = worksheet.Descendants<Row>();
20             foreach (Row row in rows)//獲取行的值
21             {
22                 foreach (Cell cell in row)
23                 {
24                     string columnValue = GetValue(cell, workbook.SharedStringTablePart);
25                 }
26             }
27         }
View Code
 1  /// <summary>
 2         /// 獲取單元格信息  這也是官方獲取值的方法
 3         /// </summary>
 4         /// <param name="cell"></param>
 5         /// <param name="stringTablePart">stringTablePart就是WorkbookPart.SharedStringTablePart,它存儲了所有以SharedStringTable方式存儲數據的子元素。</param>
 6         /// <returns></returns>
 7         public static string GetValue(Cell cell, SharedStringTablePart stringTablePart)
 8         {
 9             if (cell.ChildElements.Count == 0)
10                 return null;
11             //get cell value
12             String value = cell.CellValue.InnerText;
13             //Look up real value from shared string table
14             if ((cell.DataType != null) && (cell.DataType == CellValues.SharedString))
15                 value = stringTablePart.SharedStringTable
16                     .ChildElements[Int32.Parse(value)]
17                     .InnerText;
18             return value;
19         }
View Code  
親測可用,沒毛病!
400M左右的文件測試三次,數據量在50W條左右,耗時平均在00:01:10左右。
100M左右的文件測試一次,數據量在100W條左右,耗時00:03:47左右。

 

 1    public void Read()
 2         {
 3             DataTable dt = new DataTable();
 4             Stopwatch watch = new Stopwatch();
 5             watch.Start();
 6             using (SpreadsheetDocument spreadSheetDocument = SpreadsheetDocument.Open(@"C:\Users\Administrator\Desktop\大數據.xlsx", false))
 7             {
 8                 WorkbookPart workbookPart = spreadSheetDocument.WorkbookPart;
 9                 IEnumerable<Sheet> sheets = spreadSheetDocument.WorkbookPart.Workbook.GetFirstChild<Sheets>().Elements<Sheet>();
10                 string relationshipId = sheets.First().Id.Value = sheets.First(x => x.Name == "Sheet1").Id.Value;
11                 WorksheetPart worksheetPart = (WorksheetPart)spreadSheetDocument.WorkbookPart.GetPartById(relationshipId);
12                 Worksheet workSheet = worksheetPart.Worksheet;
13                 SheetData sheetData = workSheet.GetFirstChild<SheetData>();
14                 Row[] rows = sheetData.Descendants<Row>().ToArray();
15 
16                 int count = rows.Count();
17                 string time1 = watch.Elapsed.ToString();
18                 log.Error("excel解析完成,數據條數:" + count + ",耗時:" + time1);
19 
20                 watch.Restart();
21                 // 設置表頭DataTable
22                 foreach (Cell cell in rows.ElementAt(0))
23                 {
24                     dt.Columns.Add((string)GetCellValue(spreadSheetDocument, cell));
25                 }
26 
27                 // 添加內容
28                 for (int rowIndex = 1; rowIndex < rows.Count(); rowIndex++)
29                 {
30                     DataRow tempRow = dt.NewRow();
31 
32                     for (int i = 0; i < rows[rowIndex].Descendants<Cell>().Count(); i++)
33                     {
34                         tempRow[i] = GetCellValue(spreadSheetDocument, rows[rowIndex].Descendants<Cell>().ElementAt(i));
35                     }
36                     dt.Rows.Add(tempRow);
37                 }
38 
39                 string time2 = watch.Elapsed.ToString();
40                 log.Error("data生成結束,耗時:" + time2);
41             }
42         }
View Code

 

 1  public static string GetCellValue(SpreadsheetDocument document, Cell cell)
 2         {
 3             SharedStringTablePart stringTablePart = document.WorkbookPart.SharedStringTablePart;
 4             string value = cell.CellValue.InnerXml;
 5 
 6             if (cell.DataType != null && (cell.DataType.Value == CellValues.SharedString || cell.DataType.Value == CellValues.String || cell.DataType.Value == CellValues.Number))
 7             {
 8                 return stringTablePart.SharedStringTable.ChildElements[Int32.Parse(value)].InnerText;
 9             }
10             else //浮點數和日期對應的cell.DataType都為NULL
11             {
12                 // DateTime.FromOADate((double.Parse(value)); 如果確定是日期就可以直接用過該方法轉換為日期對象,可是無法確定DataType==NULL的時候這個CELL 數據到底是浮點型還是日期.(日期被自動轉換為浮點
13                 return value;
14             }
15         }
View Code

 

 

 

 

 

 

 

感謝:

https://www.cnblogs.com/longshanshan/p/7156036.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM