Excel Datei Laden - Slow

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 3 Antworten in diesem Thema. Der letzte Beitrag () ist von Dksksm.

    Excel Datei Laden - Slow

    Hallo,

    ich bin gerade dabei eine Excel-Datein mit C# zu öffnen und an bestimmten punkten auszulesen.
    Mein problem ist nun das mein einlesen bis zu 12 Sec dauert Oo was für mich sehr lang ist.
    Dazu muss ich sagen, das Dok. besteht aus mehreren seiten (12) und jede hat ein ungefähren gleichen aufbau, dabei variieren die Zeile nur sehr gering.

    Nun zu meiner Frage, kennt jm. eine schneller Methode oder sogar was viel besseres was ich jetzt durchs googeln nicht gefunden habe?

    - Zum Managen meiner Excel-Datei
    Spoiler anzeigen

    C#-Quellcode

    1. using Microsoft.Office.Interop.Excel;
    2. using System;
    3. namespace ArbeitssnachweisManager
    4. {
    5. public class Excel
    6. {
    7. private _Application _excel;
    8. private Workbook _workbook;
    9. public int PageCount { get => _workbook.Worksheets.Count; }
    10. public Worksheet this[int sheetIndex] => _workbook.Worksheets[sheetIndex + 1];
    11. public Worksheet this[string sheetName] => _workbook.Worksheets[sheetName];
    12. public Excel this[Worksheet sheet, int row, int col, string content] { set => WriteCell(sheet, row, col, content); }
    13. public string this[Worksheet sheet, int row, int col] { get => ReadCell(sheet, row, col); }
    14. public Excel(string path)
    15. {
    16. _excel = new Application();
    17. _workbook = _excel.Workbooks.Open(path);
    18. }
    19. public Worksheet GetPage(int sheetIndex) => _workbook.Worksheets[sheetIndex];
    20. public Worksheet GetPage(string sheetName) => _workbook.Worksheets[sheetName];
    21. public string ReadCell(int sheetIndex, int row, int col) => ReadCell(this[sheetIndex], row, col);
    22. public string ReadCell(Worksheet sheet, int row, int col)
    23. {
    24. Range r = sheet.Cells[row + 1, col + 1];
    25. return (r.Value2 ?? string.Empty).ToString();
    26. }
    27. public void WriteCell(int sheetIndex, int row, int col, string content) => WriteCell(this[sheetIndex], row, col, content);
    28. public void WriteCell(Worksheet sheet, int row, int col, string content) => sheet.Cells[row + 1, col + 1] = content;
    29. public int GetColumnsCount(int sheetIndex) => GetColumnsCount(this[sheetIndex + 1]);
    30. public int GetColumnsCount(string sheetName) => GetColumnsCount(this[sheetName]);
    31. public int GetColumnsCount(Worksheet sheet) => sheet.UsedRange.Columns.Count;
    32. public int GetRowsCount(int sheetIndex) => GetRowsCount(this[sheetIndex + 1]);
    33. public int GetRowsCount(string sheetName) => GetRowsCount(this[sheetName]);
    34. public int GetRowsCount(Worksheet sheet) => sheet.UsedRange.Rows.Count;
    35. public void Save(bool save = true)
    36. {
    37. _workbook.Close(save, Type.Missing, Type.Missing);
    38. }
    39. public void Close(bool save = true)
    40. {
    41. Save();
    42. _excel.Quit();
    43. }
    44. }
    45. }


    -- Mein eigentliches Programm
    Spoiler anzeigen

    C#-Quellcode

    1. private unsafe void MainForm_Shown(object sender, EventArgs e)
    2. {
    3. DateTime date = DateTime.Now; //Später relevant
    4. DirectoryInfo assetsFolder = new DirectoryInfo("assets"); //ordner in der die Datei liegen soll
    5. FileInfo[] assetsFiles = assetsFolder.GetFiles(); //Lesen aller datei
    6. for (int i = 0, n = assetsFiles.Length; i < n; i++) // Druchlaufen aller datein und nach meiner Datei suchen für Dynamischen Name
    7. {
    8. FileInfo selectFile = assetsFiles[i];
    9. if (selectFile.Extension == ".xls") //endung nach der ich suche identisch
    10. {
    11. Excel selectExcel = new Excel(selectFile.FullName);
    12. if (selectExcel.ReadCell(0, 0, 0) == "Arbeitszeitnachweis") //Prüfen ob in der Fixen Cell mein erkennugsmerkmal ist
    13. {
    14. _excel = selectExcel; //datei als ausgewählte setzen
    15. break; //überschreibuns gefahr
    16. }
    17. }
    18. }
    19. if (_excel == null) //falls meine Datein nicht vorhanden ist
    20. {
    21. MessageBox.Show("Es wurde keine .xls für den Arbeitsnachweis gefunden");
    22. Close();
    23. return;
    24. }
    25. TabControl tabControl = new TabControl() { Dock = DockStyle.Fill };
    26. for (int i = 0, n = _excel.PageCount; i < n; i += 1)
    27. {
    28. ExcelWorkbanche.Worksheet sheet = _excel[i]; //Seite heran holen
    29. string name = sheet.Name; //Seiten name speichern für die TapPage
    30. TabPage page = new TabPage(name); // erstellen der TabPage
    31. DataGridView dataGrid = new DataGridView { Dock = DockStyle.Fill }; //DataGridView zu darstellen der Daten
    32. DataTable table = new DataTable(); //Daten-Tabelle als source zum DataGridview
    33. int colCount = _excel.GetColumnsCount(sheet); //benutze Anzahl der Spalten vom der Seite
    34. int startRange = 6; //Position des ersten Datum *Fix
    35. int endRange = _excel.GetRowsCount(sheet); //benutzte zeilen von der Seite
    36. for (int rowMax = endRange - 1; i > startRange; rowMax -= 1)//Finden des Letzen Datum ... Durchlauf von unten
    37. {
    38. string value = _excel.ReadCell(sheet, rowMax, 0); //Wert von einer Cell holen
    39. if (!string.IsNullOrWhiteSpace(value)) //prüfen ob sie nicht leer ist
    40. {
    41. if (Regex.IsMatch(value, @"[\d\.]+")) //entspricht das format einem Datum (e.g. 01.02.)
    42. {
    43. endRange = rowMax + 1; //Position des Letzen datums Merken
    44. break; //Rausspringen wegen überschreibung
    45. }
    46. }
    47. }
    48. for (int col = 0; col < colCount; col += 1) //Durchlaufen der Spalten für den DataGridView kopf
    49. {
    50. string cell = _excel.ReadCell(sheet, 4, col); //Lesen der Cell
    51. try //Error bei doppelter namensnennung
    52. {
    53. table.Columns.Add(new DataColumn(cell)); //Spalte erstellen
    54. }
    55. catch
    56. {
    57. int c = table.Columns.Cast<DataColumn>().Count(x => x.ColumnName.Contains(cell)); //Durchzählen wie oft eine spalte mit dem selben namen vorkommt
    58. table.Columns.Add(new DataColumn($"{cell}-{i}")); //die Anzahl angängen an den Name (e.g. ABC => ABC-1)
    59. }
    60. }
    61. dataGrid.DataSource = table; //Die Source zuweisen
    62. page.Controls.Add(dataGrid); //Der Page das DataGridView übergeben
    63. tabControl.TabPages.Add(page); //Page den Tabcon ....
    64. }
    65. panel1.Controls.Add(tabControl);
    66. }

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Facebamm“ ()

    Der Zugriff auf das Excel-Dokument ist langsam also solltest du viele kleine Zugriffe vermeiden. Wenn du z.B. mit

    C#-Quellcode

    1. Excel.Range range = worksheet.UsedRange;
    2. object[,] data = (object[,])range.get_Value(Excel.XlRangeValueDataType.xlRangeValueDefault);
    dir das gesamte Sheet als Object-Array holst und damit Arbeitest, müsste das deutlich schneller gehen, als immer einzelne Zellen zu lesen. Genauso kannst du in dieses Object-Array schreiben und dann mit set_Value glaube ich wieder das gesamte Array zurück schreiben. Also im Grunde brauchst du ein Caching.
    Ob da nicht sowieso zwei Ursachen für die Geschwindigkeit verantwortlich sein könnte?
    Mir scheint es nicht sonderlich zweckmäßig zu sein, ein Tabcontroll plus die benötigten Pages zur Laufzeit zu generieren.
    Einlesen von Excel-Tabellen in DataTable oder auch das Ausgaben von DataTables nach Excel würde ich ohnehin nur mit EPPlus machen. Es programmiert sich schneller und übersichtlicher, benötigt nicht einmal ein installiertes Excel und ist auch in der Ausführung sehr performant.