Visual Basic 2013 .CSV datei auslesen und editieren

4 Antworten

Naja, ganz ohne StreamReader geht's natürlich nicht. :)

Hier ein abgewandeltes Code-Stück aus meinem letzten Projekt für eine ähnliche Aufgabe. Ist C#, aber ich denke, du wirst etwas damit anfangen können:

private void LoadCSVFile(String p_strFilename) { // Ohne Datei -> Abbruch if (!File.Exists(p_strFilename)) return; String strLine; String strHeader = ""; String strTypes = ""; // Zeilenweises Einlesen der Datei StreamReader srFile = new StreamReader(p_strFilename); while ((strLine = srFile.ReadLine()) != null) { strLine = strLine.Trim(); // Leerzeilen überspringen if (strLine == "") continue; // Die 1. Zeile beinhaltet die Spaltenheader if (strHeader == "") { strHeader = strLine; continue; } // Die 2. Zeile beinhaltet die Spaltentypen if (strTypes == "") { strTypes = strLine; continue; } // Gelesene Datenzeile aufsplitten String[] arData = strLine.Split(','); // Ab hier dann Weiterverarbeitung der gelesenen // CSV-Daten. Hier zum Beispiel: // Entfernen der optionalen " for(Int32 i = 0; i <= arData.UpperBound(0); i++) arData[i] = arData[i].Replace("\"", ""); } srFile.Close();srFile.Dispose(); }


MrHaeufele 
Beitragsersteller
 12.05.2015, 12:13

Ja sehr geil! Durch die anderen Antworten und dein Snippet, kann ich mir langsam eine Vorstellung davon machen, wie es aussehen sollte- denke ich .. Danke!

PWolff  08.05.2015, 12:15

So etwas ähnliches kommt bei uns auch immer wieder vor.

Dabei sind leider immer wieder Kommas in den einzelnen Werten. Dadurch schlägt

strLine.Split(',')

fehl.

(In VB hieße das übrigens

strLine.Split(","c)

)

Mir drängt sich die Frage auf, ob Du bei dieser Aufgabenstellung mit XML und einer SQL-Datenbank im Hintergrund nicht vielleicht besser bedient wärst als mit einer csv- Datei?


MrHaeufele 
Beitragsersteller
 08.05.2015, 04:34

Ist leider nicht möglich - es muss so sein.

Ein Beispiel findest du bei der Hilfe zur Klasse

Microsoft.VisualBasic.FileIO.TextFieldParser

in https://msdn.microsoft.com/en-us/library/cakac7e6%28VS.90%29.aspx

Schau dir auch im Object Browser (erreichbar über [F2] in der Entwicklungsumgebung) die Hilfeseiten zu den Eigenschaften an, insbesondere Delimiters und HasFieldsEnclosedInQuotes.

Die 2. Zeile kannst du in der Schleife überspringen mit

If thisTextFieldParser.LineNumber = ? Then Continue Do

(Welche Zahl dorthin kommt, wo jetzt das Fragezeichen steht, müsstest du ausprobieren - ich werd aus der Hilfe nicht ganz schlau, ob hier die Nummer der nächsten einzulesenden Zeile oder die Nummer der zuletzt eingelesenen Zeile steht. Vermutlich die nächste einzulesende, und die oberste Zeile hat die Nummer 0.)

Woher ich das weiß:Berufserfahrung – Software-Entwickler

MrHaeufele 
Beitragsersteller
 12.05.2015, 12:12

Diese Microsoft seiten sind etwas verwirrend - aber es hilft schonmal weiter, danke!

PWolff  12.05.2015, 15:19
@MrHaeufele

Hab mal ein Beispiel zusammengestellt. Steuerelemente auf der Form: Button1 und ListView1. Dateipfad und -Name entsprechend anpassen (in Path.Combine). Bilderauswertung nur angedeutet.

  Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Dim Dateiname = Path.Combine("D:\temp\csv", "gutefrage_Testdatei.csv")
Dim strÜberschriften() As String = New String() {} 'das = New String() {} dient dazu, dass der Compiler nicht meckert, weil man die Variable nicht initialisiert hat
Dim strTypen() As String = New String() {}
Dim strWerte() As String = New String() {}
Dim Werte() As Object = New Object() {}

With ListView1
.Clear()
.View = View.Details 'Details, damit man die Untereinträge sieht
'Falls Bilder berücksichtigt werden sollen
'.LargeImageList = New ImageList()
'.SmallImageList = New ImageList()
End With 'ListView1

Using tfp = New TextFieldParser(Dateiname, Encoding.Default)
With tfp
.SetDelimiters(",")
.HasFieldsEnclosedInQuotes = True
.TrimWhiteSpace = True 'Damit werden führende und am Ende stehende Leerzeichen aus den Einträgen entfernd

If Not .EndOfData() Then strÜberschriften = .ReadFields() 'die Abfrage If Not .EndOfData wegen der Angewohnheit, robust zu programmieren - das Programm soll auch bei Fehleingaben weiterlaufen
With ListView1
For i = 0 To strÜberschriften.Count - 1
'Falls Bilder berücksichtigt werden sollen
'.Columns.Add(strÜberschriften(i), .ClientSize.Width \ (strÜberschriften.Count - 1)) '"\" steht für Integer-Division (ohne Rest) 'ggf. abzgl. Icon
'falls keine Bilder berücksichtigt werden sollen
.Columns.Add(strÜberschriften(i), .ClientSize.Width \ (strÜberschriften.Count)) '"\" steht für Integer-Division (ohne Rest) 'ggf. abzgl. Icon
Next 'i = 0 To strÜberschriften.Count - 1
End With 'ListView1

If Not .EndOfData() Then strTypen = .ReadFields()

Do Until .EndOfData()
strWerte = .ReadFields()
ReDim Werte(strWerte.Count - 1)

For i = 0 To strWerte.Count - 1
Select Case strTypen(i).ToLowerInvariant() 'Umwandlung der Einträge in die jeweiligen Typen
Case "string" : Werte(i) = CType(strWerte(i), String)
Case "int" : Werte(i) = CType(strWerte(i), Integer)
Case Else : Werte(i) = strWerte(i)
If i = 0 Then 'beim ersten Durchgang eine Warnung ausgeben
MsgBox("Nicht implementierter Typ " + strTypen(i) + " angetroffen.")
End If
End Select
Next 'i = 0 To strWerte.Count - 1

Dim lvi = New ListViewItem(strWerte(0))
For i = 1 To strWerte.Count - 1 'Ab 1, da strWerte(0) schon in das Hauptelement von lvi eingetragen worden ist
'Falls Bilder berücksichtigt werden können
'If strÜberschriften(i) = "Icon" Then
' lvi.ImageKey = strWerte(i)
'ElseIf strÜberschriften(i) = "IconExportName" Then
' lvi.Tag = strWerte(i)
'Else
' lvi.SubItems.Add(strWerte(i))
'End If
'Falls keine Bilder berücksichtigt werden sollen
lvi.SubItems.Add(strWerte(i))
Next 'i = 1 To strWerte.Count - 1
ListView1.Items.Add(lvi)
Loop 'Until .EndOfData()
End With 'tfp
End Using 'tfp = New TextFieldParser(Dateiname, Encoding.Default)

End Sub
MrHaeufele 
Beitragsersteller
 13.05.2015, 07:15
@PWolff

Sieht ja echt sexy aus, aber man kann die Werte nun nicht Editieren - was aber möglich sein sollte. Deswegen dachte ich an DataGridView und hab das ganze irgendwie zusammen gewurschtelt mit dem snippet von CSANecromancer (den Hauptteil). Da kam es mir grad noch logisch vor die einzelnen Zeilen raus zu picken für die Spalten-Überschriften. Langsam weiss ich garnichts mehr.. Wie soll ich vorran gehen?:

Private Sub LoadBtn1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles LoadBtn1.Click Dim Fields() As String Dim oRow As String Dim strHeader As [String] = "" Dim strTypes As [String] = "" Dim dt = New DataTable() Dim sr = My.Computer.FileSystem.OpenTextFileReader(Path, _ System.Text.Encoding.Default) For I As Integer = 1 To ANZAHLSPALTEN dt.Columns.Add(I) ' Einfach weil ich es mit dem strHeader nicht hinbekomme, also ihn hier passend einzufügen Next Do While (sr.Peek > -1) ' Dateiende abfragen oRow = sr.ReadLine ' Eine Datenzeile lesen While (InlineAssignHelper(oRow, sr.ReadLine())) IsNot Nothing oRow = oRow.Trim() ' Die 1. oRow beinhaltet die Spaltenheader If strHeader = "" Then strHeader = oRow 'Hier fehlt mir die begabung oder ich bin einfach nur wieder zu lange wach Continue While End If ' Die 2. Zeile beinhaltet die Spaltentypen If strTypes = "" Then strTypes = oRow 'Wäre es simple und überhaupt möglich diese als Tooltip über die strHeader zu setzen? Ansonsten kann man sich auch was anderes überlegen Continue While End If Fields = oRow.Split(Seperator) Dim dr As DataRow = dt.NewRow ' Leere Datenzeile erstellen dr.ItemArray = Fields ' In DataRow speichern dt.Rows.Add(dr) ' Felder zur Datatable hinzufügen End While Loop DataGridView1.DataSource = dt ' DataTable in DataGridView zeigen und freuen End Sub

Ich hoffe der zeigt es hier nun auch richtig an.

Bekomme den strHeader nicht in dt.Columns - schließlich muss ich vorher schon angeben, wieviele Spalten das dingen hat. Das haut mich grade ziemlich von der Bahn,- der soll doch erstmal checken, wieviele Spalten der überhaupt braucht.. 

Ich sollte erstmal ne Runde schlafen...