2017-10-06 21 views
0

私はC#とWPFが新しく、大きな.xlsxファイルをデータグリッドに読み込もうとしていますが、約200+の列を持つことができます。& 100,000+の行。私の現在の方法では1時間以上かかる(私はそれを終了させませんでした)。私の形式のCSV形式の例は次のようになります。大規模な.xlsxファイルの読み込みが遅い

"Time","Dist","V_Front","V_Rear","RPM" 
"s","m","km/h","km/h","rpm" 
"0.000","0","30.3","30.0","11995" 
"0.005","0","30.3","30.0","11965" 
"0.010","0","30.3","31.0","11962" 

私は現時点でInteropを使用していますが、負荷時間を大幅に削減する別のアプローチがあるかどうかは疑問です。 SciCharts(学生ライセンスがある)を使用してこのデータをプロットし、チャンネル選択のチェックボックスを付けることを希望しますが、それは別の問題です。

.CS

private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     OpenFileDialog openfile = new OpenFileDialog(); 
     openfile.DefaultExt = ".xlsx"; 
     openfile.Filter = "(.xlsx)|*.xlsx"; 

     var browsefile = openfile.ShowDialog(); 

     if (browsefile == true) 
     { 
      txtFilePath.Text = openfile.FileName; 

      Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application(); 
      Microsoft.Office.Interop.Excel.Workbook excelBook = excelApp.Workbooks.Open(txtFilePath.Text.ToString(), 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0); 
      Microsoft.Office.Interop.Excel.Worksheet excelSheet = (Microsoft.Office.Interop.Excel.Worksheet)excelBook.Worksheets.get_Item(1); ; 
      Microsoft.Office.Interop.Excel.Range excelRange = excelSheet.UsedRange; 

      string strCellData = ""; 
      double douCellData; 
      int rowCnt = 0; 
      int colCnt = 0; 

      DataTable dt = new DataTable(); 
      for (colCnt = 1; colCnt <= excelRange.Columns.Count; colCnt++) 
      { 
       string strColumn = ""; 
       strColumn = (string)(excelRange.Cells[1, colCnt] as Microsoft.Office.Interop.Excel.Range).Value2; 
       dt.Columns.Add(strColumn, typeof(string)); 
      } 

      for (rowCnt = 2; rowCnt <= excelRange.Rows.Count; rowCnt++) 
      { 
       string strData = ""; 
       for (colCnt = 1; colCnt <= excelRange.Columns.Count; colCnt++) 
       { 
        try 
        { 
         strCellData = (string)(excelRange.Cells[rowCnt, colCnt] as Microsoft.Office.Interop.Excel.Range).Value2; 
         strData += strCellData + "|"; 
        } 
        catch (Exception ex) 
        { 
         douCellData = (excelRange.Cells[rowCnt, colCnt] as Microsoft.Office.Interop.Excel.Range).Value2; 
         strData += douCellData.ToString() + "|"; 
        } 
       } 
       strData = strData.Remove(strData.Length - 1, 1); 
       dt.Rows.Add(strData.Split('|')); 
      } 

      dtGrid.ItemsSource = dt.DefaultView; 

      excelBook.Close(true, null, null); 
      excelApp.Quit(); 


     } 
    } 

私は本当に感謝すべてのヘルプ。

+0

各行を個別に挿入するのではなく、すべてをデータバインド可能なカスタムオブジェクトの 'List'に入れる方が速いでしょう。 – DiskJunky

+0

文字列に対して多くの操作を行うため、 'StringBuilder'を使用したいことがあります。 –

+0

DataTableを埋めるためにOLEDBを使ってみましたか? – Equalsk

答えて

1

問題は、あまりにも多くの個別の読み取りがあり、Excelとアプリケーションの間で多数のリフレクションの使用とマーシャリングが発生することです。メモリ使用量が気にならない場合は、Range全体をメモリに読み込んで、セルを個別に読み取るのではなく、メモリから作業するだけです。あなたは、あなたが賢明なバッチでそれを行う必要があり、全体Rangeを読みたくない場合は

OpenFileDialog openfile = new OpenFileDialog(); 
openfile.DefaultExt = ".xlsx"; 
openfile.Filter = "(.xlsx)|*.xlsx"; 

var browsefile = openfile.ShowDialog(); 

if (browsefile == true) 
{ 
    txtFilePath.Text = openfile.FileName; 

    var excelApp = new Microsoft.Office.Interop.Excel.Application(); 
    var excelBook = excelApp.Workbooks.Open(txtFilePath.Text, 0, true, 5, "", "", true, 
     Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0); 
    var excelSheet = (Microsoft.Office.Interop.Excel.Worksheet) excelBook.Worksheets.Item[1]; 

    Microsoft.Office.Interop.Excel.Range excelRange = excelSheet.UsedRange; 

    DataTable dt = new DataTable(); 

    object[,] value = excelRange.Value; 

    int columnsCount = value.GetLength(1); 
    for (var colCnt = 1; colCnt <= columnsCount; colCnt++) 
    { 
     dt.Columns.Add((string)value[1, colCnt], typeof(string)); 
    } 

    int rowsCount = value.GetLength(0); 
    for (var rowCnt = 2; rowCnt <= rowsCount; rowCnt++) 
    { 
     var dataRow = dt.NewRow(); 
     for (var colCnt = 1; colCnt <= columnsCount; colCnt++) 
     { 
      dataRow[colCnt - 1] = value[rowCnt, colCnt]; 
     } 
     dt.Rows.Add(dataRow); 
    } 

    dtGrid.ItemsSource = dt.DefaultView; 

    excelBook.Close(true); 
    excelApp.Quit(); 
} 

:以下のコードでは、5列と103938行を持つテストファイルに3880ミリ秒で実行されます。

もう1つの最適化は、バックグラウンドスレッドでこれを実行することです。そのため、ロード中にUIをブロックすることはありません。あなたは非同期メソッドであるとTask.Runとスレッドプールのスレッドで実際の解析を実行する別の方法に解析ロジックを入れてボタンクリックハンドラを変更することができ、バックグラウンドスレッドでこれを実行するための

編集

private async void Button_Click(object sender, RoutedEventArgs e) 
{ 
    OpenFileDialog openfile = new OpenFileDialog(); 
    openfile.DefaultExt = ".xlsx"; 
    openfile.Filter = "(.xlsx)|*.xlsx"; 

    var browsefile = openfile.ShowDialog(); 

    if (browsefile == true) 
    { 
     txtFilePath.Text = openfile.FileName; 

     DataTable dataTable = await ParseExcel(txtFilePath.Text).ConfigureAwait(true); 

     dtGrid.ItemsSource = dataTable.DefaultView; 
    } 
} 

private Task<DataTable> ParseExcel(string filePath) 
{ 
    return Task.Run(() => 
    { 
     var excelApp = new Microsoft.Office.Interop.Excel.Application(); 
     var excelBook = excelApp.Workbooks.Open(filePath, 0, true, 5, "", "", true, 
      Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0); 
     var excelSheet = (Microsoft.Office.Interop.Excel.Worksheet) excelBook.Worksheets.Item[1]; 

     Microsoft.Office.Interop.Excel.Range excelRange = excelSheet.UsedRange; 

     DataTable dt = new DataTable(); 

     object[,] value = excelRange.Value; 

     int columnsCount = value.GetLength(1); 
     for (var colCnt = 1; colCnt <= columnsCount; colCnt++) 
     { 
      dt.Columns.Add((string) value[1, colCnt], typeof(string)); 
     } 

     int rowsCount = value.GetLength(0); 
     for (var rowCnt = 2; rowCnt <= rowsCount; rowCnt++) 
     { 
      var dataRow = dt.NewRow(); 
      for (var colCnt = 1; colCnt <= columnsCount; colCnt++) 
      { 
       dataRow[colCnt - 1] = value[rowCnt, colCnt]; 
      } 
      dt.Rows.Add(dataRow); 
     } 

     excelBook.Close(true); 
     excelApp.Quit(); 

     return dt; 
    }); 
} 

ハンドラは単に解析関数を呼び出し、解析関数は、バックグラウンドスレッドで実行され、それが終了したときハンドラはItemsSourceに得DataTableを割り当てることによって継続することができます。

+0

ありがとう、それは理にかなっています。バックグラウンドスレッドでこれを実行する方法についてもう少し説明できますか?歓声 –

+0

@ The-Wookie-Monster:編集を参照してください。 –

関連する問題