使用多个线程写入excel文件

时间:2015-02-05 12:42:45

标签: c# multithreading excel export-to-excel excel-interop

我正在尝试写入具有大记录的excel的数据表。我正在尝试使用分而治之的stratergy,其中每个线程被分配以写入相应的excelworkbook表。但是我获取文件是只读,单击确定覆盖文件。

class Program
{
    int processorCount = 2;
    static volatile bool processing = true;
    DataTable employeeTable = new DataTable("Employee");
    ManualResetEvent mre = new ManualResetEvent(false);

    AutoResetEvent ar = new AutoResetEvent(true);
    int record_count;
    static void Main(string[] args)
    {
        Program p = new Program();

        //Create an Emplyee DataTable

        p.employeeTable.Columns.Add("Employee ID");
        p.employeeTable.Columns.Add("Employee Name");
        for (int i = 0; i <= 2; i++)
        {
            p.employeeTable.Rows.Add(i.ToString(), "ABC");
        }
        p.record_count = p.employeeTable.Rows.Count / p.processorCount;


        Excel.Application excelApp = new Excel.Application();

        //Create an Excel workbook instance and open it from the predefined location
         Excel.Workbook excelWorkBook1 = excelApp.Workbooks.Open(@"F:\Org.xlsx");

        Thread[] threads = new Thread[3];
        for (int i = 0; i < 3; i++)
        {

            //  p.ExportDataSetToExcel(i);
            ParameterizedThreadStart ps = new ParameterizedThreadStart(p.ExportDataSetToExcel);
            threads[i] = new Thread(ps);
            threads[i].Start(new Custom() { sheetNo = i, excelWorkBook = excelWorkBook1 });
        }

        for (int j = 0; j < 3; j++)
        {
            threads[j].Join();
        }

        Console.WriteLine("Succeess");

        Console.ReadKey();



    }

    private void ExportDataSetToExcel(object sheet1)
    {

        lock (this)
        {
            bool found = false;
            Excel.Worksheet excelWorkSheet;

            int sheetNo = ((Custom)sheet1).sheetNo;
            Excel.Workbook excelWorkBook = ((Custom)sheet1).excelWorkBook;
            excelWorkSheet = (excelWorkBook).Sheets["Sheet" + ((int)sheetNo + 1).ToString()];

            for (int i = 1; i < employeeTable.Columns.Count + 1; i++)
            {
                excelWorkSheet.Cells[1, i] = employeeTable.Columns[i - 1].ColumnName;
            }

            int baseIndex = (int)sheetNo * record_count;
            for (int j = baseIndex; j < baseIndex + record_count; j++)
            {
                for (int k = 0; k < employeeTable.Columns.Count; k++)
                {
                    excelWorkSheet.Cells[j + 2, k + 1] = employeeTable.Rows[j].ItemArray[k].ToString();
                }
            }

            Console.WriteLine(sheetNo.ToString());
            Console.WriteLine("\n");

            (excelWorkBook).Save();
            (excelWorkBook).Close();
        }
    }



}**strong text**
  public class  Custom
  {
      public int sheetNo;
      public Excel.Workbook excelWorkBook;
  } 

2 个答案:

答案 0 :(得分:2)

不是通过OLE或VSTO使用互操作,而是使用EPPlusNPOI之类的库或直接使用Open XML SDK来创建Excel文件。

Interop强制您在单个线程上工作,并且您始终支付CPU互操作成本,浪费的CPU和内存以运行Excel,最后支付CPU和IO以保存文件。

另一方面,Open XML SDK和其他库甚至不需要Excel。所有操作都在内存中,您只需支付CPU和IO成本来保存文件。结果,它们的速度提高了几个数量

因此,您可以在Web和服务器应用程序中使用它们,因为使用Interop和VSTO是不可能的

EPPlus有一些很好的功能,比如从DataTable(LoadFromDataTable)或LINQ查询(LoadFromCollection)创建Excel表,这使得导出数据非常容易,例如:

using (var excelFile = new ExcelPackage(targetFile))
{
    var worksheet = excelFile.Workbook.Worksheets.Add("Sheet1");
    var tableRange=worksheet.Cells["A1"].LoadFromCollection(employees, true);
    excelFile.Save();
}

<强>更新

我刚刚在评论中读到OP想要导出大量行并认为Excel有一些限制。但事实并非如此,但情况与开始时完全不同。

自2010年以来,Excel对行数没有任何限制。只要机器有足够的内存,它就可以通过PowerPivot / PowerQuery处理多个数百万行的源。在2010年,文件大小有2GB的人为限制(以适应SharePoint),但我认为这在2013年被删除。这是一个巨大的大小,因为PowerPivot使用与Analysis Services相同的列压缩。

在这种情况下,最好的选择是创建一个带有PowerPivot连接的Excel文件,将其提供给用户并让他们随时刷新数据。

不幸的是,这是Excel的一项功能,而不是文件格式。这意味着您无法使用SDK创建包含列压缩数据的文件,但必须再次使用interop / VSTO。但在这种情况下,它的Excel会拉动和压缩数据。

答案 1 :(得分:1)

不幸的是,Excel不是多线程的。但我建议你写的写作更有效。逐个单元写入是减速的最大部分。

消除这两个因素(组织数据并将其写入)会将实际写入时间减少到可能消除同时写入它的需要。

我有一个旧的VSTO项目,我必须从数据库中编写数据集,然后将数据提取为二维数组,然后将整个数组写入工作表中的某个区域,如下所示:

Microsoft.Office.Tools.Excel.Worksheet TheSheet;


private void PublishToSheet( int totalRows, int maxColumns, ref string[,] OutputArray )
{
    Excel.Range Range = TheSheet.Range["A1", TheSheet.Cells[totalRows, maxColumns]];
    Range.NumberFormat = "@";
    Range.Value2 = OutputArray;

    LastRow = totalRows;
    LastColumn = maxColumns;

}