C#通过OleDBDataReader从大型excel文件批量复制抛出内存异常

Posted

技术标签:

【中文标题】C#通过OleDBDataReader从大型excel文件批量复制抛出内存异常【英文标题】:C# Bulk Copy via OleDBDataReader from large excel file throwing out of memory exception 【发布时间】:2019-07-18 05:40:01 【问题描述】:

我有一个大的 excel 文件(530K 行有很多列)。最终为 .xlsb 格式的 247MB。我正在尝试使用 C# 中的 BulkCopy 导入 SQL Server,但是我遇到了问题,即一旦我运行 ExecuteReader() 命令,数据读取器甚至在开始读取文件之前就耗尽了内存。

string exlConnString = $"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=_filepath;Extended Properties=\"Excel 12.0;HDR=YES;\"";
string sqlQuery = $"SELECT * FROM [SheetName]";
using OleDbConnection conn = new OleDbConnection(_connstring))     
   OleDbCommand exlCmd = new OleDbCommand(sqlQuery, conn)
   conn.Open();
   OleDbDataReader dr = exlcmd.ExecuteReader(); <---NEVER GETS PAST THIS LINE BEFORE RUNNING OUT OF MEMORY.
   SqlBulkCopy bulkCopy = new SqlBulkCopy(sqlConnString);
   bulkCopy.DestinationTable = TableName;
   while(dr.Read()) 
      bulkcopy.WriteToServer(dr);
   
   dr.Close();

我在 x86 模式下运行,因为我收到一个错误,指出我的本地计算机上没有安装 ACE 数据库,并且公司政策限制阻止我下载和安装所需的文件以在 x64 模式下运行它。

当我在较小的文件上测试代码时,代码运行得非常好,但当我在这个较大的文件上测试它时,它就不行了,所以肯定是文件大小导致了问题。任何建议或帮助将不胜感激。当批量复制用于处理大量数据时,内存不足并没有多大意义,这也意味着文件大小也会很大......

是的,我知道我应该能够在 SQL Server 中使用 OPENROWSET 或 OPENDATASOURCE 导入它,但它也已关闭,他们不会启用它,所以这不是一个选项。

【问题讨论】:

【参考方案1】:

所以你的问题是下一个。

当您尝试ExecuteReader DataReader 尝试将所有数据从您的 excel 文件读取到内存中。您可以考虑一下,就像通过 OleDbProvider 使用 excel 的专业一样。

所以我的建议是使用 csv 文件而不是 excel,因为使用 csv 文件,您可以逐行读取和解析它们。为此,我建议您使用CSV helper

【讨论】:

我需要它来处理这两个项目,我已经让它适用于 CSV 文件。原因是有些数据集不能很好地映射到 CSV 文件,需要采用 Excel 格式。对于我尝试导入的实例,它有一个 detals 字段,其中包含输入信息的人员的 cmets,该字段本身几乎包含所有定界符,这会破坏 CSV 格式。看起来我需要 Open XML SDK,它显然是为此而设计的。 我明白你的意思了!在这种情况下,Open XML 可能是最佳选择。 @MattE 导出带有自定义分隔符的 CSV 文件,例如~ ^ |.【参考方案2】:

参考此代码.. 这里 dtExcelData 是数据表变量,da 是 OleDbDataAdapter 变量。

 string excelConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=_filepath;Extended Properties='Excel 12.0;HDR=YES';";

                // Create Connection to Excel Workbook
                using (OleDbConnection connection = new OleDbConnection(excelConnectionString))
                
                    connection.Open();
                    da = new OleDbDataAdapter("Select * FROM [Sheet1$]", connection);    
                    da.Fill(dtExcelData);

                    //store data in sql server database table
                   // below connection string "conString" is I mention in app.config file.(sql server connection string to store data in sql server database)
                    string str = ConfigurationManager.ConnectionStrings["conString"].ConnectionString;
                    using (SqlConnection con = new SqlConnection(str))
                    
                        // Bulk Copy to SQL Server
                        using (SqlBulkCopy bulkCopy = new SqlBulkCopy(con))
                         
                            bulkCopy.DestinationTableName = "TableName";
                            con.Open();
                            bulkCopy.WriteToServer(dtExcelData);
                            con.Close();
                        
                                            
                    connection.Close();
                

如果对您有用,请将其标记为答案。 :)

【讨论】:

我已经用数据适配器试过了,它也有同样的问题......内存不足 仅供参考,当您使用 using 时,无需关闭连接,因为它会自动完成

以上是关于C#通过OleDBDataReader从大型excel文件批量复制抛出内存异常的主要内容,如果未能解决你的问题,请参考以下文章

使用 oledbdatareader C# 移动到下一条记录

c# - 从 ms access 数据库中随机生成数据

OleDbDatareader 十进制问题

OleDbDataReader 如何读取数字类型?

如何防止 OleDbDataReader.ExecuteReader 自动附加整数以复制列值

大型查询如何在 C#/ASP.NET MVC 4 部分中返回结果