2009-02-20 4 views
5

私はOleDb接続を使用して、かなり長い間、Excelファイルを正常に読み取ってきましたが、問題が発生しました。 Excelのスプレッドシートを最初の列に何もアップロードせずにファイルを読み込もうとしている人がいるので、その列は認識されません。どの列を紛失することなく、C#でExcelファイルを読むにはどうすればよいですか?

私は現在、次のOLEDB接続文字列使用してい

プロバイダ= Microsoft.Jet.OLEDB.4.0;
データソース= c:\ test.xls;
拡張プロパティ= "Excel 8.0; IMEX = 1;"

したがって、エクセルファイルに13個の列がある場合、返されるOleDbDataReaderには12個の列/フィールドしかありません。

洞察力があれば幸いです。

+0

最初の列に何もない場合、問題は何ですか? – StingyJack

答えて

3

SpreadsheetGear for .NETはあなたにXLSを操作するためのAPIを提供し、.NETからワークブックをXLSXです。 OleDBやExcel COMオブジェクトモデルより使いやすく高速です。 live samplesが表示されたり、free trialでご自身で試してみてください。

免責事項:私はスプレッドシートギアLLC

EDIT所有:

StingyJackを "OLEDBよりより速くより良いバックを主張している?" コメントしています。

これは妥当な要求です。私は事実が偽であることを知っているすべての主張を見るので、懐疑的であると誰かを責めることはできません。

以下は、SpreadsheetGearを使用して50,000行×10列のブックを作成し、ディスクに保存して、OleDbとSpreadsheetGearを使用して数値を合計するコードです。SpreadsheetGearは0.31秒で500Kのセルを読み取り、OleDBでは0.63秒で、2倍以上の速さで読み込みます。 SpreadsheetGearは実際にOleDBでブックを読むのに要する時間よりも短時間でブックを作成して読み込みます。

コードは次のとおりです。あなたは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

OleDbよりも速いですか?主張を裏付けるより良いこと。 – StingyJack

+0

StingyJack:私は懐疑的であるとあなたを責めません。 SpreadsheetGearがOleDbよりも実際に高速であることを示すコードで私の回答を編集しました。 –

+0

私の数字は少し異なりましたが、合理的に近い数字でした。あなたは本当にそれをあなたのサイトに投稿するべきです。 xlsコンポーネントの周りを買い物するとき、これは本当に見るべき情報でしょう。 – StingyJack

1

Excel Interopを使用してスプレッドシートを開き、直接解析するか(たとえばVBAでセルをスキャンする方法と同様)、または特定の列を入力するように強制するテンプレートを作成します。データ。

+0

interopライブラリに移動します。 LLは正しいです。 – KevDog

0

エクセルシートの形式で列ヘッダーを使用する必要がある場合は、常に13列を使用します。処理するときにヘッダー行をスキップするだけで済みます。

これは、ユーザーが期待していない順序で列を配置する状況も修正します。 (ヘッダー行の列インデックスを検出して適切に読み取り)

他の人がExcelの相互運用機能を推奨していますが、これはOleDbの方法と比較して遅いオプションです。さらに、ExcelまたはOWCをサーバーにインストールする必要があります(ライセンス供与)。

+0

ファイルには現在、ヘッダー行があります。ヘッダー行を含めるようにOleDbに指示しても(HDR = NOを使用)、それでも12列しか返さず、最初の列をスキップします。 – Austin

+0

そのHDRオプションは後方に向かって聞こえます...(http://www.connectionstrings.com/excel)をconn文字列の参照としてチェックします。 – StingyJack

+0

私はそれが後方に聞こえるのは分かっていますが、あなたはヘッダ行を与えるように伝えるためにHDR = NOを設定します(基本的にヘッダ行はデータ行であると言っています) – Austin

0

ExcelとCOMをお試しください。そうすることで、馬の口元からまっすぐに情報を得ることができます。 MSDNフォーラム上のD.アナンドから

オーバー:

Excelにプロジェクト内の参照を作成しますオブジェクトライブラリ。エクセルオブジェクトライブラリは、参照ダイアログを追加するCOMタブに追加することができます。ここで

は、C#でExcelオブジェクトモデルのいくつかの情報 http://msdn.microsoft.com/en-us/library/aa168292(office.11).aspx

+0

馬の口は噛むのに時間がかかりますので、これは大きな(> 1000行)ファイルにはあま​​り効果がありません。 – StingyJack

+1

これはサーバ環境であれば、馬の口がサーバ環境でうまく動かない – JoshBerke

+0

ええ、スピードの問題からCOMまたはInteropのルートに行ってはいけません。しかし、それは私たちがしなければならないことかもしれません。私がそのように行く前に他のアイデアは? – Austin

0

OfficeとExcelのInterop用にVisual Studio Toolsをお試しください。それは非常に簡単です使用しています。

1

おそらくExcelMapperを見ることができます。これは、強く型付けされたオブジェクトとしてExcelファイルを読み込むためのツールです。あなたのコードからExcelを読むことの詳細をすべて隠しています。 Excelに列がないか、データが列にない場合は注意が必要です。興味のあるデータを読みます。ExcelMapperのコード/実行ファイルはhttp://code.google.com/p/excelmapper/から取得できます。

関連する問題