将巨大的Excel表导入Datatable

我有一个Excel工作表,有两个选项卡。

一个是大约700K,另一个是大约25K。 问题是当我加载文件我的记忆被吃掉,它崩溃! 如何处理巨大的文件,有些甚至可能超过一百万行。

这是我目前使用的代码:

OleDbConnection cnn = new OleDbConnection("provider=Microsoft.ACE.OLEDB.12.0;Data Source='" + fileName + "';Extended Properties=Excel 12.0;"); cnn.Open(); string qry = "SELECT * FROM [Detail$]"; OleDbDataAdapter odp = new OleDbDataAdapter(qry, cnn); odp.Fill(detailTable); DataSet tmp = new DataSet(); if (detailTable.Rows.Count > 0) { Console.WriteLine("Total " + detailTable.Rows.Count + " Detail rows Loaded"); // MessageBox.Show("Input Sheet UPLOADED !"); } qry = "SELECT * FROM [Gallery$]"; OleDbDataAdapter odp1 = new OleDbDataAdapter(qry, cnn); odp1.Fill(galleryTable); if (galleryTable.Rows.Count > 0) { Console.WriteLine("Total " + galleryTable.Rows.Count + " Gallery Numbers Loaded"); // MessageBox.Show("Input Sheet UPLOADED !"); } 

好的,我可以build议你使用DbDataAdapter.Fill(Int32, Int32, DataTable[])重载方法在“块”模式下工作:

 public int Fill( int startRecord, int maxRecords, params DataTable[] dataTables ) 

使用这个方法和我的代码示例,您可以一次处理大量的行,而不是使用内存中的完整excel数据。 在每次填充之后,处理临时数据表对象,这样就可以避免内存泄漏。

这里是你如何做到这一点:

  const string fileName = "myData.xlsx"; const string excelConnString = "provider=Microsoft.ACE.OLEDB.12.0;Data Source='" + fileName + "';Extended Properties=Excel 12.0;"; using (var cnn = new OleDbConnection(excelConnString)) { cnn.Open(); const string countQuery = "SELECT COUNT(*) FROM [Detail$]"; using (var cmd = new OleDbCommand(countQuery, cnn)) { using (var reader = cmd.ExecuteReader()) { if (reader == null) return; reader.Read(); var rowsCount = ((int)reader[0]); const string query = "SELECT * FROM [Detail$]"; using (var odp = new OleDbDataAdapter(query, cnn)) { var detailTable = new DataTable(); var recordToStartFetchFrom = 0; //zero-based record number to start with. const int chunkSize = 100; while (recordToStartFetchFrom <= rowsCount) { var diff = rowsCount - recordToStartFetchFrom; int internalChunkSize = diff < 100 ? diff : chunkSize; odp.Fill(recordToStartFetchFrom, internalChunkSize, detailTable); foreach (DataRow row in detailTable.Rows) { Console.WriteLine("{1} {0}", row.ItemArray[0], row.ItemArray[1]); } Console.WriteLine("--------- {0}-{1} Rows Processed ---------", recordToStartFetchFrom, recordToStartFetchFrom + internalChunkSize); recordToStartFetchFrom += chunkSize; detailTable.Dispose(); detailTable = null; detailTable = new DataTable(); } } Console.ReadLine(); } } } 

由于您需要在内存中加载大量数据(例如,每行1M行* 1Kb〜1GB),您唯一合理的select是使用内置64位(x64)应用程序作为x86应用程序的地址空间限制(在普通x86系统上为2GB,在x64系统上为4GB)将不允许分配足够的内存。

笔记:

  • 在某些情况下,x64可能是不可能的(即缺less通过某种PInvoke使用的x64本机库)
  • 如果为行使用精心devise的自定义类,则可以在x86进程的内存中容纳更多的行。 即一些值可能会出现在您的数据库作为string,可以表示为1-4字节的枚举,而不是内存中的string。
  • 考虑将search移到DB / Excel而不是使用自定义内存中search。
  • 如果坚持使用x86,请确保不要在内存中加载超过1个数据副本。

只需select您需要的5或6列。