C# Excel Interop Slow when looping through cells

后端 未结 4 772
星月不相逢
星月不相逢 2021-02-06 05:38

I am trying to extract all text data from an Excel document in C# and am having performance issues. In the following code I open the Workbook, loop over all worksheets, and loop

4条回答
  •  [愿得一人]
    2021-02-06 06:00

    I sympathize with you pwwolff. Looping through Excel cells can be expensive. Antonio and Max are both correct but John Wu's answer sums it up nicely. Using string builder may speed things up and making an object array from the used range IMHO is about as fast as you are going to get using interop. I understand there are other third party libraries that may perform better. Looping through each cell will take an unacceptable amount of time if the file is large using interop.

    On the tests below I used a workbook with a single sheet where the sheet has 11 columns and 100 rows of used range data. Using an object array implementation this took a little over a second. With 735 rows it took around 40 seconds.

    I put 3 buttons on a form with a multi line text box. The first button uses your posted code. The second button takes the ranges out of the loops. The third button uses an object array approach. Each one has a significant performance improvement over the other. I used a text box on the form to output the data, you can use a string as you are but using a string builder would be better if you must have one big string.

    Again, if the files are large you may want to consider another implementation. Hope this helps.

    private void button1_Click(object sender, EventArgs e) {
      Stopwatch sw = new Stopwatch();
      MessageBox.Show("Start DoExcel...");
      sw.Start();
      DoExcel();
      sw.Stop();
      MessageBox.Show("End DoExcel...Took: " + sw.Elapsed.Seconds + " seconds and " + sw.Elapsed.Milliseconds + " Milliseconds");
     }
    
    private void button2_Click(object sender, EventArgs e) {
      MessageBox.Show("Start DoExcel2...");
      Stopwatch sw = new Stopwatch();
      sw.Start();
      DoExcel2();
      sw.Stop();
      MessageBox.Show("End DoExcel2...Took: " + sw.Elapsed.Seconds + " seconds and " + sw.Elapsed.Milliseconds + " Milliseconds");
    }
    
    private void button3_Click(object sender, EventArgs e) {
      MessageBox.Show("Start DoExcel3...");
      Stopwatch sw = new Stopwatch();
      sw.Start();
      DoExcel3();
      sw.Stop();
      MessageBox.Show("End DoExcel3...Took: " + sw.Elapsed.Seconds + " seconds and " + sw.Elapsed.Milliseconds + " Milliseconds");
    }
    
    // object[,] array implementation
    private void DoExcel3() {
      textBox1.Text = "";
      string Path = @"D:\Test\Book1 - Copy.xls";
      Excel.Application xl = new Excel.Application();
      Excel.Workbook WB;
      Excel.Range rng;
    
      WB = xl.Workbooks.Open(Path);
      xl.Visible = true;
      int totalRows = 0;
      int totalCols = 0;
      foreach (Excel.Worksheet CurrentWS in WB.Worksheets) {
        rng = CurrentWS.UsedRange;
        totalCols = rng.Columns.Count;
        totalRows = rng.Rows.Count;
        object[,] objectArray = (object[,])rng.Cells.Value;
        for (int row = 1; row < totalRows; row++) {
          for (int col = 1; col < totalCols; col++) {
            if (objectArray[row, col] != null)
              textBox1.Text += objectArray[row,col].ToString();
          }
          textBox1.Text += Environment.NewLine;
        }
      }
      WB.Close(false);
      xl.Quit();
      Marshal.ReleaseComObject(WB);
      Marshal.ReleaseComObject(xl);
    }
    
    // Range taken out of loops
    private void DoExcel2() {
      textBox1.Text = "";
      string Path = @"D:\Test\Book1 - Copy.xls";
      Excel.Application xl = new Excel.Application();
      Excel.Workbook WB;
      Excel.Range rng;
    
      WB = xl.Workbooks.Open(Path);
      xl.Visible = true;
      int totalRows = 0;
      int totalCols = 0;
      foreach (Excel.Worksheet CurrentWS in WB.Worksheets) {
        rng = CurrentWS.UsedRange;
        totalCols = rng.Columns.Count;
        totalRows = rng.Rows.Count;
        for (int row = 1; row < totalRows; row++) {
          for (int col = 1; col < totalCols; col++) {
            textBox1.Text += rng.Rows[row].Cells[col].Value;
          }
          textBox1.Text += Environment.NewLine;
        }
      }
      WB.Close(false);
      xl.Quit();
      Marshal.ReleaseComObject(WB);
      Marshal.ReleaseComObject(xl);
    }
    
    // original posted code
    private void DoExcel() {
      textBox1.Text = "";
      string Path = @"D:\Test\Book1 - Copy.xls";
      Excel.Application xl = new Excel.Application();
      Excel.Workbook WB;
      Excel.Range rng;
    
      WB = xl.Workbooks.Open(Path);
      xl.Visible = true;
      foreach (Excel.Worksheet CurrentWS in WB.Worksheets) {
        rng = CurrentWS.UsedRange;
        for (int i = 1; i < rng.Count; i++) {
          textBox1.Text += rng.Cells[i].Value;
        }
      }
      WB.Close(false);
      xl.Quit();
      Marshal.ReleaseComObject(WB);
      Marshal.ReleaseComObject(xl);
    }
    

提交回复
热议问题