C# C加载xlsx文件性能不好

C# C加载xlsx文件性能不好,c#,performance,excel,epplus,npoi,C#,Performance,Excel,Epplus,Npoi,我有一个关于用C加载Excel Xlsx文件的问题。我用NPOI 2.0实现了Excel加载,但性能相当差,加载时间为15到25秒,在Win7上运行10000行60列,使用IntelR CoreTM i5-3210M CPU@2.50GHz 4 CPU,~2.5GHz。我认为这是因为NPOI2.0仍处于测试阶段,所以我尝试了另一个名为EPPlus的库,加载Excel文件所需的时间仍然大致相同 以下是我如何使用EPPlus加载它: var existingFile = new FileInfo(p

我有一个关于用C加载Excel Xlsx文件的问题。我用NPOI 2.0实现了Excel加载,但性能相当差,加载时间为15到25秒,在Win7上运行10000行60列,使用IntelR CoreTM i5-3210M CPU@2.50GHz 4 CPU,~2.5GHz。我认为这是因为NPOI2.0仍处于测试阶段,所以我尝试了另一个名为EPPlus的库,加载Excel文件所需的时间仍然大致相同

以下是我如何使用EPPlus加载它:

var existingFile = new FileInfo(path);

var excelData = new ExcelViewModel(path);

// Open and read the XlSX file.
using (var package = new ExcelPackage(existingFile))
{
    // Get the work book in the file
    ExcelWorkbook workBook = package.Workbook;
    if (workBook != null)
    {
        // Here is some initializing......

        var viewSheetModel = new ExcelSheetViewModel(sheet.Name, numberOfColumns, titles);
        for (var row = titleRowIndex + 1; row <= end.Row; ++row)
        {
            var viewRowModel = new ExcelRowViewModel();

            for (int column = start.Column; column <= end.Column; ++column)
            {
                var cell = sheet.Cells[row, column];
                viewRowModel.AddCellValue(cell.Value != null ? cell.Value.ToString() : string.Empty);
            }

            viewSheetModel.Rows.Add(viewRowModel);
        }

        excelData.AddSheet(viewSheetModel);
    }
}
根据dotTrace探查器,大约40%的时间浪费在通过访问package.Workbook属性调用的get_工作簿方法上,另外30%的时间浪费在get_项和get_值调用上,还有5%的时间浪费在AddCellValue方法上,AddCellValue方法是我的数据模型,其余的时间被分配到各种方法调用上

是我做错了什么,还是这种表现正常


干杯

我发现FOR循环非常昂贵。以下是我如何在1秒多的时间内完成85000 x 26张图纸的加载

ExcelWorksheet ws = ...

Int32 maxLength = ws.Dimension.End.Row + 1;
Int32 maxWidth = ws.Dimension.End.Column + 1;

// Fetch the entire sheet as one huge range
ExcelRange cells = ws.Cells[1, 1, maxLength, maxWidth];

// cells.Values now contains a 2 dimensional object array
// Feel free to stop here

// I wanted a jagged array of type string, so I converted it.
// Start by converting the 2D array to 1D.
object[] obj_values = ((object[,]) cells.Value).Cast<object>().ToArray();

// Convert object[] to string[]
string[] str_values = Array.ConvertAll(obj_values, p => p == null ? "" : p.ToString());

// Chunk 1D array back into a jagged array and convert nulls to String.Empty
Int32 j = 0;
string[][] values = str_values.GroupBy(p => j++ / maxWidth).Select(q => q.ToArray()).ToArray();

// This was very fast compared to FOR loops!

在我看来,是的,观察到的性能对于EPPlus来说是正常的。五年后,我在EPPlus 4.5.2.1中遇到了类似的问题。在get_工作表和i5-4200U上读取的单线程电子表格中,评测提供了59%的数据,每秒管理约120000个单元格。虽然这比原始帖子中提到的50000个单元/秒有所改进,但很可能是硬件差异造成的

相比之下,SpreadsheetLight显示的似乎是i7-7700,它的速度大约是我为EPPlus测量的速度的三倍。我用C编写的自制未优化解析器每秒读取430000个单元格,从.csv文件中检索相同的数据,而上面@Tim Andersen的SpreadsheetGear注释将标准化为每秒400000个单元格。我还没有找到EPPlus和其他Excel库(如ClosedXML、NPIO、Aspose或微软的openxmlsdk)之间的比较基准

在ePlus中,我介绍的方法从最快到最慢

ExcelWorksheet.Cells[1,1,dimension.Rows,dimension.Columns].Value本质上是@Kevin M的答案,但没有一个off ExcelWorksheet.GetValuerow,column ExcelWorksheet.GetValuerow,column Excel工作表.单元格[行,列].文本 Excel工作表.单元格[行,列].值 从EPPlus 4.5.2.1开始,从ExcelRange.Value获取对象[,]的第一种方法比GetValue重载快几个百分点。通过单元格[行,列]的逐单元格访问比GetValue慢约25%


对EPPlus中代码更改的审查表明需要改进。工作簿访问在我分析过的所有路径上都很昂贵,而且它是单线程的,防止了额外核心的线性扩展。从地址转换和可调用的调用到系统中也有不必要的开销。全球化与其他库的一致性比EPPLUS快三倍。

我不能对上面的性能进行说明,但是您可以考虑查看一个可以很容易处理这个文件大小的产品。我不知道您的工作簿包含什么类型的数据,但在我的英特尔i7-3770K@3.50GHz上,加载一个包含10K行和60列随机文本/数字数据的工作簿并读取每个单元格值需要SpreadsheetGear约1秒的时间。顺便说一句,我让SpreadsheetGear在大约相同的时间内生成这些测试工作簿。如果你愿意,我可以提供更多的细节。免责声明:我为SpreadsheetGear工作。您使用的是哪个版本的ePlus?我尝试使用EPPlus 3.1.3,它的加载速度足够快。没有实际的Excel文件,很难说更多。也许Excel文件有其他类型的隐藏数据隐藏行/列/图片,多个数据密集的工作表?