将巨大的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列。
- 如何通过名称获取并比较Excel电子表格中单元格的内容?
- excel或c#或SQL解决scheme来获取期数
- dynamicparsingExcel工作表(不提供单元格范围,因为工作表中数据的位置可能会dynamic变化)
- 如何使用VSTO 2010 for Excel按名称显示工作表
- Android版Mono,读写XLSX
- NPOI xls:计算结束指数(x)超出允许范围(y..y + 2)
- 在Excel VSTO中,如何检查工作表是否属于已closures的工作簿?
- 使用Microsoft.Office.Interop.Excel创buildExcel文件而不安装Excel
- 如何保存工作表选项卡的名称导出c#