2009-02-20 5 views
5

Tôi đã sử dụng kết nối OleDb để đọc tệp excel thành công trong một thời gian ngắn, nhưng tôi đã gặp phải vấn đề. Tôi có một người đang cố gắng tải lên một bảng tính Excel không có gì trong cột đầu tiên và khi tôi cố gắng đọc tệp, nó không nhận ra cột đó.Làm cách nào để đọc tệp excel trong C# mà không bỏ sót bất kỳ cột nào?

Tôi hiện đang sử dụng chuỗi kết nối OleDb sau:

Provider = Microsoft.Jet.OLEDB.4.0;
Nguồn dữ liệu = c: \ test.xls;
Thuộc tính mở rộng = "Excel 8.0; IMEX = 1;"

Vì vậy, nếu có 13 cột trong tệp excel, thì OleDbDataReader tôi lấy lại chỉ có 12 cột/trường.

Mọi thông tin chi tiết sẽ được đánh giá cao.

+0

Nếu không có gì trong cột đầu tiên, vấn đề là gì? – StingyJack

Trả lời

3

SpreadsheetGear for .NET mang đến cho bạn một API để làm việc với xls và xlsx workbook từ NET. Nó dễ sử dụng hơn và nhanh hơn OleDB hoặc mô hình đối tượng COM của Excel. Bạn có thể xem số live samples hoặc dùng thử cho mình với free trial.

Disclaimer: Tôi sở hữu SpreadsheetGear LLC

EDIT:

StingyJack nhận xét " Nhanh hơn OleDb lại tốt hơn yêu cầu bồi thường lên?".

Đây là yêu cầu hợp lý. Tôi nhìn nhận tất cả những điều mà tôi biết là một sự thật là sai lầm, vì vậy tôi không thể đổ lỗi cho bất cứ ai vì đã hoài nghi.

Dưới đây là mã để tạo 50.000 hàng theo 10 cột bảng tính với SpreadsheetGear, lưu nó vào đĩa, và sau đó tổng hợp các số bằng OleDb và SpreadsheetGear.SpreadsheetGear đọc các tế bào 500K trong 0,31 giây so với 0,63 giây với OleDB - nhanh hơn gấp hai lần. SpreadsheetGear thực sự tạo và đọc sổ làm việc trong thời gian ít hơn cần để đọc sổ làm việc với OleDB.

Mã bên dưới. Bạn có thể dùng thử với bản dùng thử miễn phí SpreadsheetGear.

using System; 
using System.Data; 
using System.Data.OleDb; 
using SpreadsheetGear; 
using SpreadsheetGear.Advanced.Cells; 
using System.Diagnostics; 

namespace SpreadsheetGearAndOleDBBenchmark 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      // Warm up (get the code JITed). 
      BM(10, 10); 

      // Do it for real. 
      BM(50000, 10); 
     } 

     static void BM(int rows, int cols) 
     { 
      // Compare the performance of OleDB to SpreadsheetGear for reading 
      // workbooks. We sum numbers just to have something to do. 
      // 
      // Run on Windows Vista 32 bit, Visual Studio 2008, Release Build, 
      // Run Without Debugger: 
      // Create time: 0.25 seconds 
      // OleDb Time: 0.63 seconds 
      // SpreadsheetGear Time: 0.31 seconds 
      // 
      // SpreadsheetGear is more than twice as fast at reading. Furthermore, 
      // SpreadsheetGear can create the file and read it faster than OleDB 
      // can just read it. 
      string filename = @"C:\tmp\SpreadsheetGearOleDbBenchmark.xls"; 
      Console.WriteLine("\nCreating {0} rows x {1} columns", rows, cols); 
      Stopwatch timer = Stopwatch.StartNew(); 
      double createSum = CreateWorkbook(filename, rows, cols); 
      double createTime = timer.Elapsed.TotalSeconds; 
      Console.WriteLine("Create sum of {0} took {1} seconds.", createSum, createTime); 
      timer = Stopwatch.StartNew(); 
      double oleDbSum = ReadWithOleDB(filename); 
      double oleDbTime = timer.Elapsed.TotalSeconds; 
      Console.WriteLine("OleDb sum of {0} took {1} seconds.", oleDbSum, oleDbTime); 
      timer = Stopwatch.StartNew(); 
      double spreadsheetGearSum = ReadWithSpreadsheetGear(filename); 
      double spreadsheetGearTime = timer.Elapsed.TotalSeconds; 
      Console.WriteLine("SpreadsheetGear sum of {0} took {1} seconds.", spreadsheetGearSum, spreadsheetGearTime); 
     } 

     static double CreateWorkbook(string filename, int rows, int cols) 
     { 
      IWorkbook workbook = Factory.GetWorkbook(); 
      IWorksheet worksheet = workbook.Worksheets[0]; 
      IValues values = (IValues)worksheet; 
      double sum = 0.0; 
      Random rand = new Random(); 
      // Put labels in the first row. 
      foreach (IRange cell in worksheet.Cells[0, 0, 0, cols - 1]) 
       cell.Value = "Cell-" + cell.Address; 
      // Using IRange and foreach be less code, 
      // but we'll do it the fast way. 
      for (int row = 1; row <= rows; row++) 
      { 
       for (int col = 0; col < cols; col++) 
       { 
        double number = rand.NextDouble(); 
        sum += number; 
        values.SetNumber(row, col, number); 
       } 
      } 
      workbook.SaveAs(filename, FileFormat.Excel8); 
      return sum; 
     } 

     static double ReadWithSpreadsheetGear(string filename) 
     { 
      IWorkbook workbook = Factory.GetWorkbook(filename); 
      IWorksheet worksheet = workbook.Worksheets[0]; 
      IValues values = (IValues)worksheet; 
      IRange usedRahge = worksheet.UsedRange; 
      int rowCount = usedRahge.RowCount; 
      int colCount = usedRahge.ColumnCount; 
      double sum = 0.0; 
      // We could use foreach (IRange cell in usedRange) for cleaner 
      // code, but this is faster. 
      for (int row = 1; row <= rowCount; row++) 
      { 
       for (int col = 0; col < colCount; col++) 
       { 
        IValue value = values[row, col]; 
        if (value != null && value.Type == SpreadsheetGear.Advanced.Cells.ValueType.Number) 
         sum += value.Number; 
       } 
      } 
      return sum; 
     } 

     static double ReadWithOleDB(string filename) 
     { 
      String connectionString = 
       "Provider=Microsoft.Jet.OLEDB.4.0;" + 
       "Data Source=" + filename + ";" + 
       "Extended Properties=Excel 8.0;"; 
      OleDbConnection connection = new OleDbConnection(connectionString); 
      connection.Open(); 
      OleDbCommand selectCommand =new OleDbCommand("SELECT * FROM [Sheet1$]", connection); 
      OleDbDataAdapter dataAdapter = new OleDbDataAdapter(); 
      dataAdapter.SelectCommand = selectCommand; 
      DataSet dataSet = new DataSet(); 
      dataAdapter.Fill(dataSet); 
      connection.Close(); 
      double sum = 0.0; 
      // We'll make some assumptions for brevity of the code. 
      DataTable dataTable = dataSet.Tables[0]; 
      int cols = dataTable.Columns.Count; 
      foreach (DataRow row in dataTable.Rows) 
      { 
       for (int i = 0; i < cols; i++) 
       { 
        object val = row[i]; 
        if (val is double) 
         sum += (double)val; 
       } 
      } 
      return sum; 
     } 
    } 
} 
+0

Nhanh hơn OleDb? Tốt hơn là yêu cầu bồi thường. – StingyJack

+0

StingyJack: Tôi không trách bạn vì đã hoài nghi. Tôi đã chỉnh sửa phản hồi của tôi với mã chứng minh rằng SpreadsheetGear thực sự nhanh hơn OleDb. –

+0

Các con số của tôi hơi khác một chút, nhưng hợp lý gần gũi. Bạn thực sự nên đăng bài đó trên trang web của bạn. Khi mua sắm xung quanh cho một thành phần xls, điều này sẽ thực sự là thông tin để xem. – StingyJack

1

Chúng tôi luôn sử dụng Excel Interop để mở bảng tính và phân tích cú pháp trực tiếp (ví dụ như cách bạn quét qua các ô trong VBA) hoặc tạo các mẫu bị khóa để thực thi một số cột nhất định trước khi người dùng có thể lưu dữ liệu.

+0

Đi với thư viện interop. LL là đúng. – KevDog

0

Nếu có thể yêu cầu định dạng của bảng excel có tiêu đề cột, thì bạn sẽ luôn có 13 cột. Bạn chỉ cần bỏ qua hàng tiêu đề khi xử lý.

Điều này cũng sẽ khắc phục các tình huống mà người dùng đặt các cột theo thứ tự mà bạn không mong đợi. (phát hiện các chỉ mục cột trong hàng tiêu đề và đọc một cách thích hợp)

Tôi thấy rằng những người khác giới thiệu Excel interop, nhưng jeez đó là một tùy chọn chậm so với cách OleDb. Thêm vào đó nó yêu cầu Excel hoặc OWC phải được cài đặt trên máy chủ (cấp phép).

+0

Các tệp hiện có hàng tiêu đề. Ngay cả khi tôi nói với OleDb để bao gồm hàng tiêu đề (sử dụng HDR = NO), nó vẫn chỉ trả về 12 cột và bỏ qua cột đầu tiên. – Austin

+0

Tùy chọn HDR có âm thanh ngược ... kiểm tra (http://www.connectionstrings.com/excel) làm tham chiếu cho chuỗi conn. – StingyJack

+0

Tôi biết nó có vẻ ngược lại, nhưng bạn đặt HDR = NO để cho nó để cung cấp cho bạn hàng tiêu đề (về cơ bản, bạn đang nói hàng tiêu đề là một hàng dữ liệu) – Austin

0

Bạn có thể thử sử dụng Excel và COM. Bằng cách đó, bạn sẽ nhận được thông tin của bạn thẳng hình thành miệng của con ngựa, như nó được.

Từ D. Anand qua trên các diễn đàn MSDN:

Tạo một tài liệu tham khảo trong dự án của bạn sang Excel Objects Library. Thư viện đối tượng excel có thể được thêm vào trong tab COM của việc thêm hộp thoại tham chiếu.

Dưới đây là một số thông tin về mô hình đối tượng Excel trong C# http://msdn.microsoft.com/en-us/library/aa168292(office.11).aspx

+0

Những con ngựa miệng mất một lúc để nhai, vì vậy điều này sẽ không tuyệt vời như vậy cho các tập tin lớn (> 1000 hàng). – StingyJack

+1

Ngoài ra những con ngựa miệng doesnt chạy tốt trong một môi trường máy chủ nếu đây là một máy chủ environmenmt – JoshBerke

+0

Vâng, tôi muốn tránh đi COM hoặc Interop tuyến vì vấn đề tốc độ; nhưng đó có thể là những gì chúng ta phải làm. Bất kỳ ý tưởng nào khác trước khi tôi đi theo cách đó? – Austin

0

Tôi khuyên bạn nên dùng thử Công cụ Visual Studio cho Office và Excel Interop! Việc sử dụng nó rất dễ dàng.

1

Bạn có thể xem ExcelMapper. Nó là một công cụ để đọc các tập tin excel như các đối tượng được đánh máy mạnh mẽ. Nó ẩn tất cả các chi tiết của việc đọc một excel từ mã của bạn. Nó sẽ chăm sóc nếu excel của bạn thiếu một cột hoặc dữ liệu bị thiếu từ một cột. Bạn đọc dữ liệu mà bạn quan tâm. Bạn có thể lấy mã/thực thi cho ExcelMapper từ http://code.google.com/p/excelmapper/.