Mis*_*siu 3 c# epplus .net-4.5 epplus-4
我有使用EPPlus将所有记录从SQL表保存到excel工作表的函数.如果我导出少量数据一切正常,但有200多列和500 000多行我得到OutOfMemory异常.
我想修改我的代码,以便能够为每个文件保存50 000条记录.
这是我的代码适用于小数据:
private Task SaveAsync(string tableName)
{
return Task.Run(() =>
{
try
{
using (var conn = new SqlConnection(_connectionString))
{
using (var cmd = new SqlCommand(string.Format(DataQuery, tableName), conn))
{
cmd.CommandType = CommandType.Text;
cmd.CommandTimeout = 360;
conn.Open();
using (SqlDataReader sdr = cmd.ExecuteReader())
{
var fileName = string.Format(TargetFile, tableName);
if (File.Exists(fileName))
{
File.Delete(fileName);
}
sdr.Read();
var numberOfRecordsInTable = sdr.GetInt32(0);
sdr.NextResult();
using (ExcelPackage pck = new ExcelPackage(new FileInfo(fileName)))
{
ExcelWorksheet ws = pck.Workbook.Worksheets.Add("Results");
int count = sdr.FieldCount;
int col = 1, row = 1;
for (int i = 0; i < count; i++)
{
ws.SetValue(row, col++, sdr.GetName(i));
}
row++;
col = 1;
while (sdr.Read())
{
for (int i = 0; i < count; i++)
{
var val = sdr.GetValue(i);
ws.SetValue(row, col++, val);
}
row++;
col = 1;
}
//autosize
ws.Cells[ws.Dimension.Address].AutoFitColumns();
//autofiltr
ws.Cells[1, 1, 1, count].AutoFilter = true;
}
}
conn.Close();
}
}
}
catch (Exception e)
{
Debug.WriteLine("Error at: " + Thread.CurrentThread.ManagedThreadId);
Debug.WriteLine(e);
}
});
}
Run Code Online (Sandbox Code Playgroud)
和我修改过的代码,每个文件分割50 000条记录:
private Task SaveAsync2(string tableName)
{
return Task.Run(() =>
{
try
{
using (var conn = new SqlConnection(_connectionString))
{
using (var cmd = new SqlCommand(string.Format(DataQuery, tableName), conn))
{
cmd.CommandType = CommandType.Text;
cmd.CommandTimeout = 360;
conn.Open();
using (SqlDataReader sdr = cmd.ExecuteReader())
{
var fileName = string.Format(TargetFile, tableName,"");
if (File.Exists(fileName))
{
File.Delete(fileName);
}
sdr.Read();
var max = sdr.GetInt32(0);
int filesCount = 1;
if (max > 50000)
{
fileName = string.Format(TargetFile, tableName, filesCount);
}
sdr.NextResult();
ExcelPackage pck = new ExcelPackage(new FileInfo(fileName));
ExcelWorksheet ws = pck.Workbook.Worksheets.Add("RESULTS");
int count = sdr.FieldCount;
int col = 1, row = 1;
for (int i = 0; i < count; i++)
{
ws.SetValue(row, col++, sdr.GetName(i));
}
row++;
col = 1;
while (sdr.Read())
{
for (int i = 0; i < count; i++)
{
var val = sdr.GetValue(i);
ws.SetValue(row, col++, val);
}
row++;
col = 1;
if (row > 50000)
{
pck.Save();
filesCount++;
fileName = string.Format(TargetFile, tableName, filesCount);
pck = new ExcelPackage(new FileInfo(fileName));
ws = pck.Workbook.Worksheets.Add("RESULTS");
count = sdr.FieldCount;
col = 1;
row = 1;
for (int i = 0; i < count; i++)
{
ws.SetValue(row, col++, sdr.GetName(i));
}
row++;
col = 1;
}
}
//autosize
ws.Cells[ws.Dimension.Address].AutoFitColumns();
//autofiltr
ws.Cells[1, 1, 1, count].AutoFilter = true;
pck.Save();
}
}
conn.Close();
}
}
catch (Exception e)
{
Debug.WriteLine("Error at: " + Thread.CurrentThread.ManagedThreadId);
Debug.WriteLine(e);
}
});
}
Run Code Online (Sandbox Code Playgroud)
基本上这工作正常,但在我的代码的第一个版本中,我使用内部using语句中的所有内容,当在第二个版本中我调用相同的代码两次.
rows x columns?我发现EPPlus应该处理超过百万行的信息,但没有我所拥有的那么多列.我认为我可以用单列导出数百万行,但对于200多列,我可以限制50 000行.我想知道是否有数量(行x列)将限制我的导出将正常工作.我希望导出函数是通用的,所以当我传递50个列的数据表时,它将导出例如每个文件100 000行,对于2列,它将导出每个文件50万行.我在过去使用EPPlus时遇到了内存限制,最终生成了多个.xlsx文件作为解决方法(类似于你的方法).另一种方法是将编译器设置更改为仅针对64位(如果您可以在不支持32位平台的情况下使用).我记得,EPPlus是针对"任何CPU"编译的,所以如果您可以将代码更改为目标"x64",这可能会放宽内存限制并允许您生成单个.xlsx文件.针对x64可能会在我的情况下起作用,但直到事后我才想到它,所以我没有机会进行测试.
更新: 我刚刚使用EPPlus 3.1.3进行了快速测试,创建了500,000行,每行70列.在生成内存不足异常之前,我的32位应用程序能够生成大约119,000行.在将目标切换到x64之后,它成功生成了所有500,000行,尽管它花了很长时间.创建实际工作表只需几分钟,但ExcelPackage.SaveAs()花了将近20分钟.RAM消耗也非常高(大约11GB的RAM).生成的.xlsx为220MB,32位Excel无法打开(内存不足). 底线:定位x64可能不是一个可行的解决方案; 你最好将输出分成多个.xlsx文件.
我很想删除这个答案,因为它已经证明是一个死路一条,但决定留下它以防万一它可以帮助别人在将来避开这条道路.
| 归档时间: |
|
| 查看次数: |
9365 次 |
| 最近记录: |