【问题标题】:Optimizing c# excel read / write to file优化 c# excel 读取/写入文件
【发布时间】:2015-03-17 19:38:42
【问题描述】:

所以我有这个 大约 2200 行的 excel,我需要读取和写入 txt 文件,问题是它需要太多时间,我被告知 读取/写入文件通常需要时间,因为它是自然的,所以我尝试只读一次 excel 文件,使用 stringBuilder 并按行写入(没有尝试存储所有文本并写入整个 .txt 文件)

但是,有什么办法可以加快速度吗?

选择较小的范围,例如只有 1 行?用 \n 作为换行符构建一个巨大的字符串,然后将所有内容写入.txt?

这是我的代码示例

using Excel = Microsoft.Office.Interop.Excel;
[...]
xlApp = new Excel.Application();
xlWorkBook = xlApp.Workbooks.Open("C:/Users/MyUser/Desktop/SomeFolder/my_excel.xlsx", 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
Excel.Range allRange = xlWorkSheet.UsedRange;
try
{
    System.IO.StreamWriter file = new System.IO.StreamWriter("C:\\test.txt");
    String line = "";
    //StringBuilder line;
    for (int row = 1; row <= allRange.Rows.Count; row++) //These are up to thousand sometimes
    {
        if (allRange.Value2[row, 1] != "")
        {
            //line = new StringBuilder();
            for (int column = 1; column <= 6; column++)
            {
                //Console.WriteLine(allRange.Value2[row, column]);
                line += allRange.Value2[row, column];
                if (column != 6)
                {
                    line += "|";
                    //line.Append("|");
                }
            }
            file.WriteLine(line);
            line = "";
        }
        else
        {
            MessageBox.Show("Should've not reached here.");
            break;
        }
    }
    file.Close();
    }
catch (Exception ex)
{
    MessageBox.Show("Couldn't write file: " + ex.ToString());
}

顺便说一句,我正在使用 .NET v4.0.30319... 我认为(在 Environment.Version.ToString() 上说)

或 .NET v4.5.51209(在“帮助”>“关于 Microsoft Visual Studio”上显示)

【问题讨论】:

  • 2,200 行听起来并不多。为什么你不能一口气读/写整个文件?这是最快的,所以如果速度是问题,那就这样做。
  • 我教过我正在做的事情,至少在读取 xlsx 文件时,但不是在写入时,构建“巨大”字符串真的更快吗? (每行大约 45~50 行加上换行符 "\n" 乘以 2200 行,在一个字符串/stringBuilder 变量中大约有 100,000 个字符)
  • 写起来肯定更快。 100,000 个字符真的不是“巨大的”,它大约是 200k,在现代记忆术语中是花生——大约是网页上单个横幅图像的大小。就阅读而言,您被 excel interop 拖慢了速度,这可能是主要瓶颈。也许您应该将阅读阶段与写作阶段分开。首先将所有数据读入内存,然后再写入 - 这样您就可以分析这两种操作并查看哪个最慢且最需要注意。
  • 是的,我刚刚进行了分析,显然问题出在读取,选择“大”范围 Excel.Range allRange = xlWorkSheet.UsedRange; ([A,1],[AD,2210]) 并读取值一个单元一个单元,比选择一个更小的范围需要更多的时间(我只需要前 6 列)。虽然写入文件需要不到 1 秒的时间。所以现在我可以使用 OpenXML SDK 尝试@sławomir-rosiek 建议的解决方案

标签: c# .net excel optimization excel-interop


【解决方案1】:

我认为这段代码运行缓慢的主要原因是由于使用了 Excel Interop。它很慢。而不是尝试使用 OpenXML SDK - 它是操作 Office 2007+ 文档(包括 *.xlsx)的库。 ExcelInterop 速度要快得多,并且不需要在机器上安装 Excel 实例。主要缺点是它无法打开 XLS 文件。以下是如何阅读大文档的示例:https://msdn.microsoft.com/EN-US/library/office/gg575571.aspx

还可以尝试使用 StopWatch 或任何分析器并测量代码中最慢的部分。

【讨论】:

    【解决方案2】:

    我对 Excel Interop 还是很陌生,但这里有一些我最近改进的代码。性能从大约 30 秒缩短到不到 2 秒。

                            //This method is very slow.
                            // Storing Each row and column value to excel sheet
                            //for (int k = 0, k2 = 2; k < table.Rows.Count; k++, k2++)
                            //{
                            //    for (int l = 0, l1 = 1; l < table.Columns.Count; l++, l1++)
                            //    {
                            //        //ExcelApp.Cells[k2, l1] =
                            //        //    table.Rows[k].ItemArray[l].ToString();
                            //        ExcelApp.Cells[k2, l1] =
                            //            table.Rows[k][l].ToString();
                            //    }
                            //}
    
                            ////////////////
    
                            //See if this method is faster
                            // transform formated data into string[,]
    //                        var excelData = new string[table.Rows.Count, table.Columns.Count];
                            var excelData = new object[table.Rows.Count, table.Columns.Count];
                            for (int rowJ = 0; rowJ < table.Rows.Count; rowJ++)
                            {
                                for (int colI = 0; colI < table.Columns.Count; colI++)
                                {
    //                                excelData[rowJ, colI] = table.Rows[rowJ][colI].ToString();
                                    excelData[rowJ, colI] = table.Rows[rowJ][colI];
                                    //excelData[colI, rowJ] = "test";
                                }
                            }
                            //<Code to set startLoc and endLoc removed>
    
                            Range valRange = ExcelApp.get_Range(startLoc, endLoc);
                            valRange.Value2 = excelData;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-17
      • 1970-01-01
      相关资源
      最近更新 更多