【问题标题】:Improve performance in converting large execl file to list of objects提高将大型 excel 文件转换为对象列表的性能
【发布时间】:2016-07-04 08:27:41
【问题描述】:

我知道这个问题已经被问过很多次了。但我无法从其中任何人那里获得太多帮助。

我不想将 excel 转换为数据表,但我希望将其转换为对象列表并发送到服务器端进行处理。

如果它有超过 2K 行,它应该会抛出一个错误。目前我正在做的事情是这样的:

   using (var excel = new ExcelPackage(hpf.InputStream))
    {
        var ws = excel.Workbook.Worksheets["Sheet1"];

        for (int rw = 4; rw <= ws.Dimension.End.Row; rw++)
        {
            if (ws.Cells[rw, 1].Value != null)
            {
                int headerRow = 2;

                GroupMembershipUploadInput gm = new GroupMembershipUploadInput();

                for (int col = ws.Dimension.Start.Column; col <= ws.Dimension.End.Column; col++)
                {
                    var s = ws.Cells[rw, col].Value;

                    if (ws.Cells[headerRow, col].Value.ToString().Equals("Existing Constituent Master Id"))
                    {
                        gm.cnst_mstr_id = (ws.Cells[rw, col].Value ?? (Object)"").ToString();
                    }
                    else if (ws.Cells[headerRow, col].Value.ToString().Equals("Prefix of the constituent(Mr, Mrs etc)"))
                    {
                        gm.cnst_prefix_nm = (ws.Cells[rw, col].Value ?? (Object)"").ToString();
                    }
                    else if (ws.Cells[headerRow, col].Value.ToString().Equals("First Name of the constituent(Mike)"))
                    {
                        gm.cnst_first_nm = (ws.Cells[rw, col].Value ?? (Object)"").ToString();
                    }
                    .....................
                    .....................


                    }
            }

                    iUploadedCnt = iUploadedCnt + 1; //Increase the count by 1
                }

                if (lgl.GroupMembershipUploadInputList.Count < 2003) //Check for the uploaded list count
                {

                       //throw the error

                 }

但这种方法似乎很慢。

excel 到列表的转换对我来说似乎很慢。例如,当我上传超过 2k 条记录时,列表首先转换为列表,然后检查计数是否超过 2003。这个过程肯定比较慢。

如何以更快/更好的方式实现它?

【问题讨论】:

  • “慢”是什么意思?读取excel很慢?或者发送到服务器很慢?顺便提一句。我没有看到任何发送到服务器的代码。
  • 我建议将问题的标题更改为“提高将大文件转换为 excel 的性能”之类的内容,因此不要误导您的问题在于转换本身。
  • @x... excel 到列表的转换对我来说似乎很慢,当我上传超过 2k 条记录时,列表首先转换为列表,然后检查计数是否超过 2003。这个过程比较慢。
  • @Veverke 感谢您的建议。
  • 如何使用 Stopwatch 类并逐行测量,哪一行慢?

标签: c# excel performance epplus


【解决方案1】:

你做了很多不必要的重复字符串处理。对于每一行,如果它们符合某个预定义值,则再次检查列标题。 (例如if (ws.Cells[headerRow, col].Value.ToString().Equals("Existing Constituent Master Id"))

您可以在开始解析所有行并创建例如Dictionary&lt;int, SomeEnum&gt; 之前执行此操作一次,它将列号映射到特定的枚举值。解析行时,您可以在字典中快速查找,哪个列映射到哪个属性。

此外,您定义了var s = ws.Cells[rw, col].Value;,但从不使用它。相反,当您将其分配给对象的属性时,您会再次读取此单元格值。你可以在这里进行必要的转换和检查,然后只使用s;

// define this enum somewhere
enum ColumPropEnum {
   cnst_mstr_id,  cnst_prefix_nm, ...
}

//define this prop somewhere
Dictionary<int, ColumnPropEnum> colprops = new Dictionary<int, ColumnPropEnum>();

//do this once before processing all rows
for (int col = ws.Dimension.Start.Column; col <= ws.Dimension.End.Column; col++) {
    if (ws.Cells[headerRow, col].Value.ToString().Equals("Existing Constituent Master Id")) 
        colprops.Add(col, ColumnPropEnum.cnst_mstr_id);
    else if (ws.Cells[headerRow, col].Value.ToString().Equals(" ..."))
        colprops.Add(col, ColumnPropEnum.cnst_prefix_nm);
    ...
}


//now use this dictionary in each row    
for (int rw = 4; rw <= ws.Dimension.End.Row; rw++)
{
....
    for (int col = ws.Dimension.Start.Column; col <= ws.Dimension.End.Column; col++) {

        //the single ? checks, whether the Value is null, if yes it returns null, otherwise it returns ToString(). Then the double ?? checks whether the result if the operation is null, if yes, it assigns "" to s, otherwise the result of ToString(); 
        var s = ws.Cells[rw, col].Value?.ToString() ?? "";
        ColumnPropEnum cp;
        if (colpros.TryGetValue(col, out cp)) {
            switch (cp) {
                case cnst_mstr_id: gm.cnst_mstr_id = s; break;
                case cnst_prefix_nm: gm.cnst_prefix_nm = s; break;
                ...
            }
        }
    }

}

我不确定您在哪个位置将此对象添加到列表或将其上传到服务器,因为这不是代码的一部分。但它可能更快,如果您有必要的非空值计数,则首先仅检查每行的第一列,如果没有则抛出错误,仅在您没有时才进行所有其他处理不要抛出错误。

int rowcount = 0;
//If you need at minimum 2000 rows, you can stop after you count 2000 valid rows
for (int rw = 4; rw <= ws.Dimension.End.Row && rowcount < 2000; rw++)        
{
    if (ws.Cells[rw, 1].Value != null) rowcount++
}

if (rowcount < 2000) {
    //throw error and return
} 

//else do the list building and uploading

【讨论】:

    猜你喜欢
    • 2017-08-14
    • 1970-01-01
    • 2023-04-08
    • 2021-08-12
    • 1970-01-01
    • 2023-01-21
    • 2021-11-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多