我在C#中构建了一个脚本,它以CSV格式获取大型数据文件,并以Excel 2007+格式分成两个输出文件。我有完全符合所有要求的代码,但在相对较小的源文件上运行save_files()
方法需要大约15秒。我想知道是否有更快的方法来做我正在做的事情。
第一个输出最终将最多180列125,000个点写入excel文件。 (代码的15秒运行仅使用了20列)。 output1_temp_array
是List<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秒,所以我知道这可能比现在更快。
答案 0 :(得分:0)
所以在 MUCH 深入研究OpenXML之后,我采用了一种混合解决方案,它并没有真正解决问题,但至少让它更快。
对于第一个输出文件,我坚持使用原始方法。我试用SpreadsheetLight并发现没有writerow
或range.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秒。