Visual Basic 2013 .CSV datei auslesen und editieren
Hallo zusammen, ich möchte, wie im titel schon sichtlich, einfach eine .csv Datei auslesen und diese auch bearbeiten können. Die CSV-Datei ist mit , getrennt und würde z.B. so aussehen:
"Name","TID","Resource","Percentage","Icon","IconExportName"
"String","String","String","int","String","String"
"Min","TID_RESOURCE_10","XP",10,"ic/custom.sc","icon_xp_small"
"Keks","TID_RESOURCE_50","XP",50,"ic/custom.sc","icon_xp_medium"
"Max","TID_RESOURCE_FULL","XP",100,"ic/custom.sc","icon_xp_big"
Das ist nun ein Beispiel welches alle möglichen formen beinhaltet, die ich benötige. Getrennt mit , und Werte innerhalb von " aber auch ohne!
Jetzt bleibt nur die Frage, wie lese ich diese beispiel.csv aus und kann sie in meiner Form bearbeiten?! (Der Pfad wird natürlich einfach bestimmt "C:\CSV-DateiOrdner\csvdatei.csv")
Zeile 1 gibt die Namen der darunter aufgelisteten werte an und somit auch die gerde benötigten Spalten. Zeile 2 kann einfach ignoriert werden oder als ToolTip über die ersten Werte (Titel) gelegt werden. (Zur not kann man die auch mit in die Tabelle einbinden - die höhe dieser Zellen kann man ja verkleinern und als untertitel bezeichnen) Die Restlichen Zeilen geben natürlich jeweils den rest an, also die Werte der zum Titel gehörigen option/Spalte.
Ich hoffe ich habe nun nichts vergessen zu sagen und es ist verständlich genug. Ich bin dankbar für Codes &-beispiele oder auch vernünftige Tutorials.
(Keine aussagen wie " Nimm DataGridView und machs mit StreamReader" oder so ein Zeug !!! Wenn ich mir "denken" könnte wie es geht, würde ich nicht nach code beispielen o.ä. fragen.)
Gruß Patrick.
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(); }
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!
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?
kannst du damit was anfangen?:
http://stackoverflow.com/questions/11118678/convert-csv-data-to-datatable-in-vb-net
abschnitt:
Use OleDb
provider to read CSV and pouplate the DataTable
.
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.)
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
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...
Diese Microsoft seiten sind etwas verwirrend - aber es hilft schonmal weiter, danke!