2010-10-21 29 views
30

Tôi đang xuất một ma trận 1200 X 800 (indexMatrix) sang tệp excel bằng cách sử dụng tiêu chuẩn Microsoft.Office.Interop.Excel. Các ứng dụng hoạt động, chỉ là nó thực sự thực sự thực sự chậm (ngay cả đối với ma trận 100 x 100). Tôi cũng xuất khẩu trong một tập tin văn bản thông qua một TextWriter một nó hoạt động gần như ngay lập tức. Có cách nào để xuất sang tệp excel nhanh hơn không?Microsoft.Office.Interop.Excel thực sự chậm

Đây là mã của tôi:

 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"); 

Trả lời

49

Bạn đang cập nhật từng ô riêng lẻ. Điều đó sẽ rất chậm. Nếu bạn nghĩ về nó, mỗi khi bạn cập nhật một ô, một cuộc gọi RPC sẽ được kết hợp với quy trình Excel.

Sẽ nhanh hơn nhiều hơn nếu bạn chỉ định mảng giá trị hai chiều cho một phạm vi Excel có cùng kích thước trong một câu lệnh duy nhất (một cuộc gọi cross-process) thay vì 1200 x 800 = 960.000 các cuộc gọi quá trình.

Cái gì như:

// 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); 

Trên thực tế, để được pedantic, có ba chéo quá trình gọi trong đoạn mã trên (.Cells, .get_Resize và .set_Value), và có hai cuộc gọi mỗi lần lặp trong mã của bạn (.Có được và ẩn .set_Value) với tổng số 1200 x 800 x 2 = 1,920,000.

Note range.get_Resizerange.set_Value là cần thiết cho một phiên bản cũ của thư viện interop Excel Tôi đã sử dụng khi bài này lần đầu tiên tác giả. Những ngày này, bạn có thể sử dụng range.Resizerange.Value như được ghi chú trong nhận xét của @ The1nk.

+0

dường như có vấn đề tại .get_Resize. Dường như nó không tồn tại. – Alex

+0

tại dòng excel.range, lỗi sau xuất hiện '' Hệ thống .__ ComObject 'không chứa định nghĩa cho' get_Resize '' – Alex

+0

Tôi nghĩ bản chỉnh sửa sẽ sửa lỗi đó. Các ô [1,1] không trả về một đối tượng Range - vì vậy nó cần phải được cast. – Joe

13

Excel interop là không bao giờ được nhanh chóng. Về cơ bản, bạn đang điều khiển từ xa một cá thể của ứng dụng Excel. Bạn có thể có nhiều thành công hơn bằng cách tạo tệp CSV và sau đó sử dụng Excel interop để chuyển đổi tệp này thành tệp .xls hoặc .xlsx

+1

+1 Cách tiếp cận tốt và điều này đảm bảo nhanh hơn, vì tệp CSV có nhiều khả năng là văn bản hơn tệp, để lớp 'TextWriter' có thể xử lý nó. –

+0

Yup, đó là phương pháp ưa thích của tôi. Mặc dù bạn gặp vấn đề khi các giá trị ô chứa các dòng mới, vì các giá trị đó sẽ làm tăng chỉ mục hàng của bạn. Bất cứ ai có bất kỳ lời khuyên cho vấn đề này? – Yevgeniy

+1

Trả lời nhận xét trên của tôi: sử dụng import-csv (powershell) hoặc một hàm thư viện tương đương sẽ xử lý các tình huống lộn xộn với các ký tự định tính và dòng mới được sử dụng trong các giá trị trường. – Yevgeniy

2

Sử dụng Value2 để tăng tốc độ nhanh; Hiển thị excel trước khi điền dữ liệu

6

Tôi gặp sự cố tương tự khi đọc tệp excel cực lớn và mất hơn 2 giờ sử dụng interop.

Tôi đã thử sử dụng ClosedXml và quy trình mất chưa đầy 10 giây. ClosedXml

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

Cũng nên nhớ interop sẽ không hoạt động trên máy chủ của bạn, trừ khi bạn đã cài đặt excel. ClosedXml không cần cài đặt excel.

+0

Lần đầu tiên sử dụng ClosedXML và REALLY thật nhanh. Tôi đã sử dụng InsertData với một mảng các mảng và một đối số. Rất trơn tru so với HSSF và HSSF craziness của POI và ngoại lệ COM của interop !!! +1 – Mzn

2

Tắt ScreenUpdating trước khi viết bất kỳ dữ liệu, Application.ScreenUpdating = FALSE sau đó bật ở cuối mã = TRUE

2

ClosedXML là một điều kỳ diệu, đó là một thỏa thuận lớn nhanh hơn và dễ dàng hơn để sử dụng.

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 

Bạn cài đặt bằng cách sử dụng nu Nhận gói. https://www.nuget.org/packages/ClosedXML

+0

Yup, thật ấn tượng. Đã đi từ khoảng 4,5 giờ đến 5 phút. Github: https://github.com/closedxml/closedxml – Andres

0

Có ba cách để làm điều này, 2 trong số đó được đề cập trong câu trả lời khác nhau bởi những người khác:

  1. Trực tiếp thiết lập giá trị của một loạt trong excel đến các mảng 2D.
  2. Ghi dữ liệu vào tệp CSV, sau đó sử dụng interop để lưu tệp CSV dưới dạng tệp xls hoặc xlsx.
  3. Ghi dữ liệu vào tệp CSV, sau đó sử dụng tính năng kết nối dữ liệu để sử dụng CSV làm nguồn dữ liệu và nhập dữ liệu.

Cả ba phương pháp trên đều rất nhanh. Tôi có thể ghi dữ liệu với kích thước 90000 hàng và 100 cột trong khoảng 6 giây.

P.S. Tuy nhiên, họ không giải quyết được vấn đề của tôi với định dạng dữ liệu cho đường viền, kiểu phông chữ, màu sắc, hợp nhất ô, v.v.

Các vấn đề liên quan