Laden...

Interop.Excel Beim Lesen von Zeilen werden Inhalte beim Range.Cells abgeschnitten

Erstellt von DontBlameMe vor 5 Jahren Letzter Beitrag vor 5 Jahren 1.907 Views
D
DontBlameMe Themenstarter:in
6 Beiträge seit 2016
vor 5 Jahren
Interop.Excel Beim Lesen von Zeilen werden Inhalte beim Range.Cells abgeschnitten

Werte Forumsgemeinde,

momentan arbeite ich an einem Tool, was etwas Voodoo in einer csv-Datei machen soll. Da dieses Voodoo doch etwas größer ist wie gedacht, möchte ich es in einem C#-Programm lösen anstatt in einer VBA-Skriptschlacht. Die eigentlich Funktion spielt vorerst keine Rolle. Sondern habe ich schon Probleme beim auslesen der Daten aus der csv-tabelle.
Es werden für mich nicht nachvollziehbare Zeileninhalte weggelassen.

Grundlegendes: verwendet wird Visual Studio 2017, Excel 365 und eine csv-Datei mit Tabulator als Delimiter.
Der Teil der csv mit dem ich momentan teste und bei dem mir die Fehler aufgefallen sind sieht wie folgt aus:


VB_1_CEB10_ERG\tSIMATIC S5 ETHERNET LAYER 4\tS5-Transport (CP1413-1)
VB_1_CEB10_ERG\tSIMATIC S5 ETHERNET LAYER 5\tS5-Transport (CP1413-1)
VB_1_CEB10_ERG\tSIMATIC S5 ETHERNET LAYER 6\tS5-Transport (CP1413-1)
VB_1_CEB10_ERG\tSIMATIC S5 ETHERNET LAYER 7\tS5-Transport (CP1413-1)
VB_1_CEB10_ERG\tSIMATIC S5 ETHERNET LAYER 8\tS5-Transport (CP1413-1)
VB_1_CEB10_ERG\tSIMATIC S5 ETHERNET LAYER 9\tS5-Transport (CP1413-1)
VB_1_CEB10_ERG\tSIMATIC S5 ETHERNET LAYER 10\tS5-Transport (CP1413-1)
VB_1_CEB10_ERG\tSIMATIC S5 ETHERNET LAYER 11\tS5-Transport (CP1413-1)
VB_1_CEB10_ERG\tSIMATIC S5 ETHERNET LAYER 18\tS5-Transport (CP1413-1)
VB_1_CEB10_ERG\tSIMATIC S5 ETHERNET LAYER 19\tS5-Transport (CP1413-1)

Es gibt eine Klasse, die für das lesen der Zeilen zuständig ist. Darin ist folgendes definiert:

 using Excel = Microsoft.Office.Interop.Excel; 

    public void OpenExcelTable()
    {
      if (this.ExcelFileIsValid != true)
      {
        return;
      }
      try
      {
        Excel.Application xlApp;
        Excel.Workbook xlWorkBook;
        Excel.Worksheet xlWorkSheet;
        Excel.Range range;
        
        xlApp = new Excel.ApplicationClass();
        xlWorkBook = GetWorkBook(xlApp);        //Oeffnet die ExcelDatei
        xlWorkSheet = (Excel.Worksheet) xlWorkBook.Worksheets.get_Item(1);
        range = xlWorkSheet.UsedRange;

        App = xlApp;
        WorkBook = xlWorkBook;
        Range = range;
      }
      catch (Exception ex)
      {
        MessageBox.Show(@"Fehler in ReadExcel: " + ex.Message);
      }
    }

    
    private Excel.Workbook GetWorkBook(Excel.Application xlApp)
    {
      return xlApp.Workbooks.Open(
        FilePath, // Filename
        Type.Missing,
        Type.Missing,
        Excel.XlFileFormat.xlCSV, // Format
        Type.Missing,
        Type.Missing,
        Type.Missing,
        Type.Missing,
        '\t', // Delimiter
        Type.Missing,
        Type.Missing,
        Type.Missing,
        Type.Missing,
        Type.Missing,
        Type.Missing);
    }


    public List<string> GoThroughExcelCells(int startRow, int endRow, int column, bool isDBrelated)
    {
      var range = Range;
      if (range == null)
      {
        UserForm.StatusLabel1.Text = @"Die Exceltabelle enthält keine Einträge";
        return null;
      }
      List<string> valuesList = new List<string>();

      //Gehe das Tabellenblatt im gewünschten Bereich durch
      for (int rangeCnt = startRow; rangeCnt <= endRow; rangeCnt++)
      {
        //Hier haben wir Zugriff auf jede Zeile
        if (((Excel.Range) range.Cells[rangeCnt, 1]).Value2 != null)
        {
          try
          {
            var rowValues = (string)((Excel.Range) range.Cells[rangeCnt, 1]).Value2;
            var values = rowValues.Split('\t');
            var stringHelper = values[column - 1];

            if (isDBrelated)
            {
              var arrHelper = values[column - 1].Split(',');
              stringHelper = arrHelper[0];
            }
            if(!valuesList.Contains(stringHelper))
            {
              valuesList.Add(stringHelper);
            }
          }
          catch(Exception ex)
          {
            //MessageBox.Show("Hier hats gekracht Zeile : " + rangeCnt + Environment.NewLine + 
            Environment.NewLine + ex.Message);
            UserForm.StatusLabel1.Text = @"Es gab einen Fehler  beim Auslesen der Exceldaten";
          }
        }
      }
      return valuesList;
    }

Die Methoden an sich funktionieren eigentlich tadellos. Das Problem liegt bei dieser Zeile


var rowValues = (string)((Excel.Range) range.Cells[rangeCnt, 1]).Value2;

Denn wenn in einer Zeile der csv eine "9" steht wird die Zeile ab diesem Punkt einfach abgeschnitten. Also aus


VB_1_CEB10_ERG\tSIMATIC S5 ETHERNET LAYER 9\tS5-Transport (CP1413-1)
VB_1_CEB10_ERG\tSIMATIC S5 ETHERNET LAYER 19\tS5-Transport (CP1413-1)

wird:


VB_1_CEB10_ERG\tSIMATIC S5 ETHERNET LAYER 
VB_1_CEB10_ERG\tSIMATIC S5 ETHERNET LAYER 1

Jetzt weiß ich nicht an was es liegen kann. Ich habe schon etwas mit der Konfiguration des Excel.Workbook rumprobiert, aber ohne Erfolg. Das einzige was ich dabei festgestellt habe ist, dass wenn ich den Delimiter auf ';' setze schneidet es mir die Zeilen bei jedem "i" ab. Wenn ich den Delimiter auf 'ö' setze werden die Zeilen bei "1_" und "2_" abgeschnitten.
Ich bekomme keine Exceptions oder anderen Fehlermeldungen.
An was könnte diese Verhalten liegen? Stimmt die Konfiguration von Excel.Workbook nicht oder habe ich etwas in meinem Aufruf verbockt?
Wäre schön wenn mir jemand die Augen öffnen könnte, denn mittlerweile bin ich etwas Codeblind.
Danke euch im Voraus für eure investierte Zeit.

Mit besten Grüßen
DontBlameMe

C
2.121 Beiträge seit 2010
vor 5 Jahren

Was Excel da macht weiß ich leider nicht.
Brauchst du wirklich Excel um die Daten zu bearbeiten? Eine Tab-getrennte Zeile aufsplitten und wieder zu einer solchen zusammensetzen ist recht simpel, sofern die Daten einem passenden Muster folgen. Das was du dann draus machen willst passiert sowieso schon in C# und nicht in Excel. Also warum diesen umständlichen Umweg gehen?

D
DontBlameMe Themenstarter:in
6 Beiträge seit 2016
vor 5 Jahren

Hallo chilic,

Ich wüsste nicht wie ich das sauberer lösen kann, da in einer zu lesenden csv-Datei drei Tabellen mit unterschiedlichen Strukturen enthalten sind. Das liegt daran, dass die csv von einem Exportprogramm so ausgegeben wird.
Was ich schon überlegt habe ist die csv einmalig in mehrere Listen oder ein 2-D-Array einzutragen, und dann die Listen zu bearbeiten und eine neue csv daraus zu erstellen. Allerdings erschien mir dieser Weg etwas umständlich, da ich dann gefühlt aus jeder Zeile mit Excel-Anweisung 10 Zeilen Array- bzw. Listenbefehle bauen müsste.

Aber wenn jemand einen Vorschlag hat wie ich das Problem anders, vielleicht sogar etwas perfomanter lösen kann bin ich für alles offen.

Um das besser abschätzen zu können. Hier das oben genannte "Voodoo" was passieren soll.
Eine CSV-Datei enthält 3 Tabellen. Es gibt mehrere CSVs, die aber alle die gleiche Spaltenstruktur haben.
Tabelle1 : 5 Spalten 3 Headerzeilen zwischen 1 - 100 Zeilen
Tabelle2: 5 Spalten 3 Headerzeilen zwischen 20 - 300 Zeilen
Tabelle3: 23 Spalten 3 Headerzeilen zwischen 200 - 20000 Zeilen

Tabelle1 und 2 werden nicht verändert sondern nur ausgelesen, um mit den Werten das Verhalten des Programms zu parametieren.
In der Tabelle3 werden in bis zu 5 Spalten pro Zeile Werte geändert. Entweder werden alle Zeilen verändert oder durch die Parametrierung nur Teilbereiche. Je nach Bereich der Tabelle gibt es ein anderes Änderungsverhalten für die entsprechenden Zeilenwerte.

D
DontBlameMe Themenstarter:in
6 Beiträge seit 2016
vor 5 Jahren

Ich habe das ganze jetzt mal mit einem StreamReader und einem Mehrdimensionalen Array ausprobiert und muss zu geben ich bin überrascht.
Die CSV wird mit einem StreamReader und einem Splitbefehl in ein 2-Dimensionales Array eingetragen und es wird auch alles sauber eingetragen.
Großer Pluspunkt es ist auch um einiges schneller als die Excel-Variante. Da war ich wohl etwas zu verkopft und hab mich von dem Tipp mit Excel etwas in die Irre führen lassen.

hier wird das Array erzeugt:


public string[,] GetCsvDataInArray()
    {
      var listOfRows = new List<string>();

      StreamReader streamReader = new StreamReader(FilePath);

      var rowData = streamReader.ReadLine();

      while ((rowData = streamReader.ReadLine()) != null)
      {
        listOfRows.Add(rowData);
      }

      var csvAsArray = new string[listOfRows.Count,23];

      var rowCount = 0;
      foreach (var row in listOfRows)
      {
        var rowSplitter = row.Split(_delimiter, StringSplitOptions.None);

        var columnCount = 0;
        foreach (var columnValue in rowSplitter)
        {
          csvAsArray[rowCount, columnCount] = columnValue;
          columnCount++;
        }

        rowCount++;
      }

      return csvAsArray;
    }
  }

Und hier hole ich mir die gewünschten Werte


public List<string> GoThroughCsvData(int startRow, int column, int endRow = 0, bool isDbRelated = false)
    {
      var returnList  = new List<string>();

      endRow--;
      column--;
      startRow = startRow - 2;
      if (endRow == -1)
      {
        endRow = CsvAsArray.GetLength(0);
      }

      for (int i = startRow; i <= endRow; i++)
      {
        var stringHelper = CsvAsArray[i, column];

        if(isDbRelated)
        {
          var dbStringHelper = stringHelper.Split(',');
          stringHelper = dbStringHelper[0];
        }

        if (!returnList.Contains(stringHelper))
        {
          returnList.Add(stringHelper);
        }
      }

      return returnList;
    }
  }

Danke Chilic für die Antwort dadurch habe ich mir nochmal Gedanken gemacht.