• 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:UsersAdministratorDesktop大数据.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

  • 相关阅读:
    终于以一个ACMer的名义开通博客了。。
    Struts学习笔记一
    Matplotlib画图
    设计模式第一集——策略模式
    Hibernate学习笔记
    在linux下加python path【转】
    linux学习笔记
    C#3.0初体验
    asp.net中使用ffmpeg
    常用的正则表达式(经典)
  • 原文地址:https://www.cnblogs.com/PrintY/p/14002881.html
Copyright © 2020-2023  润新知