【发布时间】:2014-11-27 01:02:08
【问题描述】:
我在 C# 中构建了一个脚本,该脚本采用 CSV 格式的大型数据文件,并拆分为 Excel 2007+ 格式的两个输出文件。我有满足所有要求的完整工作代码,但在相对较小的源文件上运行我的 save_files() 方法需要大约 15 秒。我想知道是否有更快的方法来做我正在做的事情。
第一个输出最终将多达 180 列(每列 125,000 个点)写入 excel 文件。 (代码的 15 秒运行只使用了 20 列)。 output1_temp_array 是一个 List<string[,]>,每个列表项都包含一个包含 125k 数据点的字符串数组。 (它被定义为二维数组,因为 Excel 的 Range.Value2 需要一个二维数组,但实际上它是 125k x 1 项宽。)
第二个输出最终以 1 行写入 195 列。填充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 秒,所以我知道这可能比现在更快。
【问题讨论】:
-
您是否考虑过使用 OpenXML SDK 而不是 COM?它可能会更快,因为它不必打开 excel。显然,这将意味着重大的重构,但如果您遇到性能问题,则值得考虑。
-
我同意 Greg 的观点,使用 Openxml 是一种更好的方法。如果它不需要太多重构,你可能想要采用 openxml 方式。
-
你知道你代码的哪一部分是瓶颈吗?是在构建数据吗?写入文件?一些分析可以帮助您缩小范围。
-
我将研究 OpenXML。我发布的代码几乎是瓶颈;构建数组的所有代码都需要不到半秒的时间(包括将所有 15MB 以上的数据从 CSV 读取到源数组中)。即使我注释掉 output1 写入,也需要 5 秒。
标签: c# excel performance save