为什么写入Excel范围所需的时间比C#.NET中的预期要长得多?

时间:2014-11-27 01:02:09

标签: c# excel performance save

我在C#中构建了一个脚本,它以CSV格式获取大型数据文件,并以Excel 2007+格式分成两个输出文件。我有完全符合所有要求的代码,但在相对较小的源文件上运行save_files()方法需要大约15秒。我想知道是否有更快的方法来做我正在做的事情。

第一个输出最终将最多180列125,000个点写入excel文件。 (代码的15秒运行仅使用了20列)。 output1_temp_arrayList<string[,]>,每个列表项包含一个包含125k数据点的字符串数组。 (它被定义为2D数组,因为Excel的Range.Value2需要一个2D数组,但实际上它是125k x 1项宽。)

第二个输出最后写入195列1行。填充data_temp_array的方式(它也是List<string[,]),我必须将其转换为temp_array,然后将该temp_array写入Excel范围。

以下是一些代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Excel;
using MyExcel = Microsoft.Office.Interop.Excel;

namespace TransposeAThing
{
    public partial class Form1 : Form
    {
        private void save_files()
        {
            MyExcel.Application excelApp = null;
            MyExcel.Workbook excelWorkbook = null;
            MyExcel.Worksheet worksheet = null;
            MyExcel.Range range = null;
            excelApp = new MyExcel.Application();
            excelApp.DefaultSaveFormat = XlFileFormat.xlOpenXMLWorkbook;
            excelApp.Visible = false;

            //Write data into first output file
            excelWorkbook = excelApp.Workbooks.Open(xlsOutput1_Filename, 1, false, 5, "", "", false, MyExcel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);
            worksheet = excelWorkbook.Worksheets.get_Item("Output Data");

            for (int i = 0; i < output1_temp_array.Count(); i++)
            {
                range = worksheet.get_Range((MyExcel.Range)worksheet.Cells[1, i + 2], (MyExcel.Range)worksheet.Cells[output1_temp_array[i].Length, i + 2]);
                range.set_Value(Type.Missing,output1_temp_array[i]);
            }
            excelWorkbook.Save();
            excelWorkbook.Close();

            //Write data into second output file
            string[,] temp_array;
            temp_array = new string[1,data_temp_array.Count()];

            for (int i = 0; i < data_temp_array.Count(); i++)
            {
                temp_array[0,i] = data_temp_array[i][0,0];
            }

            excelWorkbook = excelApp.Workbooks.Open(xlsData_Filename, 1, false, 5, "", "", false, MyExcel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);
            worksheet = excelWorkbook.Worksheets.get_Item("Aggregate Data");

            int start_row = worksheet.UsedRange.Rows.Count + 1;
            range = worksheet.get_Range((MyExcel.Range)worksheet.Cells[start_row, 1], (MyExcel.Range)worksheet.Cells[start_row, worksheet.UsedRange.Columns.Count]);

            range.Value2 = temp_array;
            excelWorkbook.Save();

            GC.Collect();
            GC.WaitForPendingFinalizers();

            if (worksheet != null)
            {
                Marshal.FinalReleaseComObject(worksheet);
            }
            if (excelWorkbook != null)
            {
                excelWorkbook.Close(true, Type.Missing, Type.Missing);
                Marshal.FinalReleaseComObject(excelWorkbook);
            }
            if (excelApp != null)
            {
                excelApp.Quit();
                Marshal.FinalReleaseComObject(excelApp);
            }
        }
    }
}

为什么完成这个过程需要这么长时间?关于如何加快速度的任何提示?

作为参考,我写的同样做的Python脚本在同一个数据上花了大约2.3秒,所以我知道这可能比现在更快。

1 个答案:

答案 0 :(得分:0)

所以在 MUCH 深入研究OpenXML之后,我采用了一种混合解决方案,它并没有真正解决问题,但至少让它更快。

对于第一个输出文件,我坚持使用原始方法。我试用SpreadsheetLight并发现没有writerowrange.setValue()方法,因此编写大量单元格最终成为嵌套for循环。这证明非常慢。

private void save_files()
{
    MyExcel.Application excelApp = null;
    MyExcel.Workbook excelWorkbook = null;
    MyExcel.Worksheet worksheet = null;
    MyExcel.Range range = null;
    excelApp = new MyExcel.Application();
    excelApp.DefaultSaveFormat = XlFileFormat.xlOpenXMLWorkbook;
    excelApp.Visible = false;

    excelWorkbook = excelApp.Workbooks.Open(xlsOutput1_Filename, 1, false, 5, "", "", false, MyExcel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);
    worksheet = excelWorkbook.Worksheets.get_Item("Output Data");

    for (int i = 0; i < output1_temp_array.Count(); i++)
    {
        range = worksheet.get_Range((MyExcel.Range)worksheet.Cells[1, i + 2], (MyExcel.Range)worksheet.Cells[output1_temp_array[i].Length, i + 2]);
        range.set_Value(Type.Missing, output1_temp_array[i]);
    }
    excelWorkbook.Save();
    excelWorkbook.Close();

但是,对于第二个数据输出,SpreadsheetLight肯定会缩短时间:

    SLDocument data_file = new SLDocument(xlsData_Filename, "Aggregate Data");
    SLWorksheetStatistics data_file_info = new SLWorksheetStatistics();
    data_file_info = data_file.GetWorksheetStatistics();
    int start_row = data_file_info.NumberOfRows + 1;

    for (int i = 0; i < data_temp_array.Count(); i++)
    {
        data_file.SetCellValue(start_row, i + 1, data_temp_array[i]);
    }
}

使用此解决方案,现在生成相同的文件需要8.5秒而不是15秒。