web-dev-qa-db-ja.com

Microsoft.Office.Interop.Excelは本当に遅い

標準のMicrosoft.Office.Interop.Excelを使用して、1200 X 800マトリックス(indexMatrix)をExcelファイルにエクスポートしています。アプリは動作しますが、実際には本当に本当に遅いです(100 x 100マトリックスでも)。また、TextWriterを使用してテキストファイルをエクスポートすると、ほぼ瞬時に動作します。 Excelファイルにすばやくエクスポートする方法はありますか?

ここに私のコードがあります:

        Excel.Application xlApp=new Excel.Application();
        Excel.Workbook xlWorkBook;
        Excel.Worksheet xlWorkSheet;
        object misValue = System.Reflection.Missing.Value;

        //xlApp = new Excel.ApplicationClass();
        xlWorkBook = xlApp.Workbooks.Add(misValue);

        xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
        for (int i = 0; i < 800; i++)   //h
            for (int j = 0; j < 1200; j++)
                xlWorkSheet.Cells[i+1,j+1] =indexMatrix[i][j];


        xlWorkBook.SaveAs("C:\\a.xls", Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue);
        xlWorkBook.Close(true, misValue, misValue);
        xlApp.Quit();

        releaseObject(xlWorkSheet);
        releaseObject(xlWorkBook);
        releaseObject(xlApp);

        MessageBox.Show("Excel file created , you can find the file c:\\csharp-Excel.xls");
41
Alex

個々のセルを更新しています。それは非常に遅くなります。考えてみると、セルを更新するたびに、RPC呼び出しがExcelプロセスにマーシャリングされます。

現在の1200 x 800 = 960,000のクロスではなく、単一のステートメント(1つのクロスプロセス呼び出し)で同じ次元のExcel範囲に値の2次元配列を割り当てると、muchより高速になります。プロセス呼び出し。

何かのようなもの:

// Get dimensions of the 2-d array
int rowCount = indexMatrix.GetLength(0);
int columnCount = indexMatrix.GetLength(1);
// Get an Excel Range of the same dimensions
Excel.Range range = (Excel.Range) xlWorkSheet.Cells[1,1];
range = range.get_Resize(rowCount, columnCount);
// Assign the 2-d array to the Excel Range
range.set_Value(Excel.XlRangeValueDataType.xlRangeValueDefault, indexMatrix);

実際には、上記のコードには3つのプロセス間呼び出し(.Cells、.get_Resizeおよび.set_Value)があり、コードの反復ごとに2つの呼び出し(.Cells getおよび暗黙的な.set_Value)があります。合計1200 x 800 x 2 = 1,920,000。

range.get_Resizeおよびrange.set_Valueは、この投稿が最初に作成されたときに使用していた古いバージョンのExcel相互運用ライブラリに必要でした。最近ではrange.Resizeおよびrange.Value @ The1nkのコメントに記載されているとおり。

65
Joe

Excelの相互運用が高速になることはありません。基本的に、Excelアプリケーションのインスタンスをリモート制御しています。 CSVファイルを作成し、Excel相互運用機能を使用してこれを.xlsまたは.xlsxファイルに変換すると、さらに成功する可能性があります。

15
Yuliy

非常に大きなExcelファイルを読み取るときに同様の問題が発生し、相互運用を使用して2時間以上かかりました。

ClosedXmlを使用してみましたが、処理に10秒もかかりませんでした。 ClosedXml

// To loop 
Sheet.Row(y).Cell(x).Value

また、Excelがインストールされていない限り、サーバーで相互運用が機能しないことに注意してください。 ClosedXmlにはExcelをインストールする必要はありません。

9
MIKE

データを書き込む前にScreenUpdatingをオフにします、Application.ScreenUpdating = FALSEその後、コードの最後でオン= TRUE

7
Paul Roberts

Value2を使用して高速化します。データを入力する前にExcelを表示する

2
Siarhei Kuchuk

ClosedXMLは奇跡であり、非常に高速で使いやすいです。

var workbook = new XLWorkbook();//create the new book

var worksheet = workbook.Worksheets.Add("Computer Install");// Add a sheet
worksheet.Cell(1,1).Value = "PC Name";// (Row, column) write to a cell

workbook.SaveAs(@"LIC documents.xlsx");// Save the book

Nu Getパッケージを使用してインストールします。 https://www.nuget.org/packages/ClosedXML

2
Chong Ching

これを行うには3つの方法があり、そのうち2つは他の人による異なる回答で言及されています。

  1. Excelの範囲の値を2D配列に直接設定します。
  2. データをCSVファイルに書き込み、次に相互運用機能を使用してCSVファイルをxlsまたはxlsxファイルとして保存します。
  3. データをCSVファイルに書き込み、データ接続機能を使用してCSVをデータソースとして使用し、データをインポートします。

上記の3つの方法はすべて非常に高速です。約6秒で90000行と100列のサイズのデータ​​を書き込むことができました。

追伸ただし、境界線、フォントスタイル、色、セルマージなどのデータの書式設定に関する問題は解決しませんでした。

0
Sanjit