C#IronXL(Excel)+LINQ内存问题



我的目标是找到Excel中包含特定文本的所有单元格。Excel相当大(大约2Mb(,大约有22张表格。从历史上看,我们在Interop上有问题,所以我找到了IronXL,我喜欢它的操作方式。

问题是,在某个时刻,RAM内存增加到2Gb以上,当然速度非常慢。

我知道物化问题,所以在使用LINQ时,我尽量避免使用ToList()Count()

第一个";"问题";我在IronXL中发现,Cell类没有任何字段指定包含它的工作表名称,所以我将代码分为两部分:

  1. LINQ查找包含文本的所有单元格
  2. 然后,我迭代所有以前的结果,以存储在自定义类MyCell中找到的所需单元格信息+工作表名称

自定义类:

class MyCell
{
public int X;
public int Y;
public string Location;
public string SheetName;
public MyCell(int x, int y, string location, string sheetName)
{
X = x;
Y = y;
Location = location;
SheetName = sheetName;
}
}

这是我的代码:

List<MyCell> FindInExcel(WorkBook wb, string textToFind)
{
List<MyCell> res = new List<MyCell>();
var cells = from sheet in wb.WorkSheets
from cell in sheet
where cell.IsText && cell.Text.Contains(textToFind)
select new { cell, sheet };
foreach (var cell in cells)
{
res.Add(new MyCell(cell.cell.ColumnIndex, cell.cell.RowIndex, cell.cell.Location, cell.sheet.Name));
}
return res;
}

为了测试我的方法,我调用:

WorkBook excel = WorkBook.Load("myFile.xlsx");
var results = FindInExcel(excel, "myText");

当我执行和调试代码时发生的事情确实非常奇怪。LINQ查询执行得非常快,在我的例子中,我得到了2个结果。然后它开始在foreach中迭代,前两次的值被添加到列表中,所以,一切都是完美的。但第三次,当它评估是否有其他项目可用时,是当内存达到2Gb时,大约需要10秒。

当我这样做的时候,我观察到了同样的行为:

int count = cells.Count()

我知道这是在具体化结果,但我不明白的是,为什么我在foreach中如此快地得到了2个第一个结果,而且只是在最后一步内存增加了。

看到这种行为,很明显,代码在某个地方知道已经找到了多少项,而不必调用Count(),否则第一次调用";foreach";被调用。

只是想知道我是否疯了,我试着把这个小代码放在FindInExcel方法中:

int cnt = 0;
foreach (var cell in cells)
{
res.Add(new MyCell(cell.cell.ColumnIndex, cell.cell.RowIndex, cell.cell.Location, cell.sheet.Name));
cnt++;
if (cnt == 2)
break;
}

在最后一种情况下,我没有内存问题,我最终得到了一个包含2个项目的List,其中包含我想要的单元格,并且没有任何内存问题。

我错过了什么?有没有办法在不具体化结果的情况下完成我想要做的事情?我甚至试着转到.NET Framework 4.8.1,看看是否修复了一些错误,但我得到了同样的行为。

注意:如果我在一个小型Excel中使用此代码,它运行得非常快。

提前谢谢!

我已经发现了这个问题。有一张表格,其中隐藏的公式被扩展到最后一个单元格(M1048576(,因此它正在所有这些单元格中搜索值。一旦移除,就不再存在内存问题。

谢谢你们!

最新更新