我的目标是查找Excel中包含特定文本的所有单元格。Excel相当大(约2Mb),大约有22个工作表。以前我们在使用Interop
时遇到过问题,所以我找到了IronXL
,我喜欢它的操作方式。
问题是,在某个时候,RAM内存增加到2GB以上,当然速度非常慢。
我知道实体化问题,所以我在使用LINQ时尽量避免使用ToList()
或Count()
。
我在IronXL
中发现的第一个"问题"是Cell
类没有任何字段指定包含它的工作表名称,因此我将代码分为两部分:
- LINQ查找包含文本的所有单元格
1.然后,我在所有先前的结果中进行迭代,以将所需的单元格信息+工作表名称存储在我的自定义类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
中迭代,前2次的值被添加到列表中,所以,一切都很完美。但是第3次,当它评估是否有其他项可用时,是当内存达到2GB时,大概需要10秒。
当我这样做时,我观察到了同样的行为:
int count = cells.Count()
我知道这是具体化的结果,但我不明白的是,为什么我得到的2个第一个结果在foreach
这么快,它只是在最后一步的内存增加。
看到这种行为,似乎很清楚代码知道在某处找到了多少项,而不必调用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;
}
在最后一种情况下,我没有内存问题,我最终得到了一个List
的2个项目与我想要的单元格,没有任何内存问题。
我错过了什么?有没有什么方法可以在不实现结果的情况下完成我正在尝试做的事情?我甚至试图移动到.NET Framework 4.8.1
,看看是否修复了一些bug,但我得到了同样的行为。
注意:如果我在一个小的Excel中使用这段代码,它运行得非常快。
提前感谢您!
1条答案
按热度按时间a1o7rhls1#
我已经发现了这个问题。有一个工作表中的隐藏公式扩展到了最后一个单元格(M1048576),所以它正在搜索所有这些单元格中的值。一旦删除,就不再有内存问题了。
谢谢你们!