VB.Net editing a CSV (or delimited file) - vb.net

I would like to know a way (of course I want to know the best way) to edit a csv file, preferably without having to read the original and write the results to a new one.
Example 1: I want to split the contents of a column into two columns 123abc into 123, abc
Example 2: I want to remove letters from the beginning of a column AB123 into 123
Clarification: I do not need help solving my examples; I just need to be pointed in the right direction of reading and editing the same file.
Here is a code example of using a temporary file that seems to me is too slow
Dim currentLine as string()
tempFile.AutoFlush = True
Do Until origFile.EndOfData
currentLine = origFile.ReadFields
currentLine(1) = currentLine(1).Replace("ABC","") 'would convert ABC123 to 123
For index as Integer = 0 to currentLine.Count - 2
tempFile.Write(currentLine(index) & ",")
Next
tempFile.Write(currentLine(currentLine.Count - 1))
tempFile.WriteLine()
Loop
tempFile.Flush()
tempFile.Dispose()
origFile.Dispose()
IO.File.Copy(tempFile,OrigFile,True)
IO.File.Delete(tempFile)

You really will be best off writing a new file. You can write to a temporary file, delete the old file and rename the new file as the old file.
Something like:
Imports System.IO
Module Module1
Sub Main()
Dim tempfile = Path.GetTempFileName()
Dim inputFile = "C:\Temp\input.txt"
Using sw = New StreamWriter(tempfile)
Using MyReader As New Microsoft.VisualBasic.FileIO.TextFieldParser(inputFile)
MyReader.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited
MyReader.Delimiters = New String() {","}
Dim currentRow As String()
While Not MyReader.EndOfData
Try
currentRow = MyReader.ReadFields()
If currentRow.Count >= 2 Then
currentRow(1) = currentRow(1).Replace("ABC", "")
End If
sw.WriteLine(String.Join(",", currentRow))
Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
MsgBox("Line " & ex.Message & " is invalid. Skipping")
End Try
End While
End Using
End Using
File.Delete(inputFile)
File.Move(tempfile, inputFile)
End Sub
End Module
(Basically copying the TextFieldParser example from http://msdn.microsoft.com/en-us/library/microsoft.visualbasic.fileio.textfieldparser.readfields.aspx )

You can use ADO to connect to the CSV file. See here for more info:
How to read a CSV file into a .NET Datatable
However, I would recommend simply loading it into an array and then writing it back out with simple file IO methods. It's just a lot less code and overhead:
For Each row As String In File.ReadAllLines("C:\test.csv")
For Each column As String In row.Split(New String() {","}, StringSplitOptions.None)
' Do work
Next
Next
And then something like this to save the file:
File.WriteAllLines(rows)

Related

Text file split in blocks vb.net

I am trying to go through my text file and create a new file that will contain only the text I require. My current line looks like:
Car-1I
Colour-39
Cost-328
Dealer-28
Car-2
Colour-30
Cost-234
For each block of text I would like to read the first line, if the first line ends with an I, then read the next line, if that line contains a colour 39, then I would like to save the whole block of text to another file. If these two conditions aren't met, I dont want to save my values to the new text file.
Before anything about saving my values in classes are mentioned, these blocks of text can vary in size and values, so I dont always have a set range of values which is why i need to skip to the blank line
IO.File.WriteAllText("C:\Users\test2.txt", "") 'write to new file
Dim sKey As String
Dim sValue As Integer
For Each filterLine As String In File.ReadLines("C:\Users\test.txt")
sKey = Split(filterLine, ":")(0)
sValue = Split(filterLine, ":")(1)
If Not sValue.EndsWith("I") Then
ElseIf sValue.EndsWith("I") Then
End If
Next
Another method, using File.ReadLines to read lines of text from file. This method doesn't load all the text in memory, it reads from disc single lines of text, so it can also be useful when dealing with big files.
You could loop the IEnumerable collection it returns, but also use its GetEnumerator() method to control more directly when to move to the next line, or move more then one lines forward.
Its Enumerator.Current object returns the line of text currently read, Enumerator.MoveNext() moves to the next line.
A StringBuilder is used to store the strings when a match found. Strings are added to the StringBuilder object using its AppendLine() method.
This class is useful when dealing with strings that you need to store, compare and discard (or modify) quickly: since string are immutable, when you use String variables directly, especially in loops, you generate a whole lot of garbage that slows down any procedure quite a lot.
The blocks of text stored in the StringBuilder object are then written to a destination file using a StreamWriter with explicit encoding set to UTF-8 (writes the BOM). Its methods include asynchronous versions: WriteLine() can be replaced by awaitWriteLineAsync() to allow an async procedure.
Imports System.IO
Imports System.Text
Dim sourceFilePath = "<Path of the source file>"
Dim resultsFilePath = "<Path of the destination file>"
Dim sb As New StringBuilder()
Dim enumerator = File.ReadLines(sourceFilePath).GetEnumerator()
Using sWriter As New StreamWriter(resultsFilePath, False, Encoding.UTF8)
While enumerator.MoveNext()
If enumerator.Current.EndsWith("I") Then
sb.AppendLine(enumerator.Current)
enumerator.MoveNext()
If enumerator.Current.EndsWith("39") Then
While Not String.IsNullOrWhiteSpace(enumerator.Current)
sb.AppendLine(enumerator.Current)
enumerator.MoveNext()
End While
sWriter.WriteLine(sb.ToString())
End If
sb.Clear()
End If
End While
End Using
This will work:
Dim strFile As String = "c:\Test5\Source.txt"
Dim strOutFile As String = "c:\Test5\OutPut.txt"
Dim strOutData As String = ""
Dim SourceGroups As String() = Split(File.ReadAllText(strFile), vbCrLf + vbCrLf)
For Each sGroup As String In SourceGroups
Dim OneGroup() As String = Split(sGroup, vbCrLf)
If Strings.Right(OneGroup(0), 1) = "I" And (Strings.Right(OneGroup(1), 2) = "39") Then
If strOutData <> "" Then strOutData += (vbCrLf & vbCrLf)
strOutData += sGroup
End If
Next
File.WriteAllText(strOutFile, strOutData)
Something like this should work:
Dim base, i, c as Integer
Dim lines1$() = File.ReadLines("C:\Users\test.txt")
c = lines1.count
While i < c
if Len(RTrim(lines1(i))) Then
If Strings.Right(RTrim(lines1(i)), 1)="I" Then
base = i
i += 1
If Strings.Right(RTrim(lines1(i)), 2)="39" Then
While Len(RTrim(lines1(i))) 'skip to the next blank
i += 1
End While
' write lines1(from base to (i-1)) here
Else
While Len(RTrim(lines1(i)))
i += 1
End While
End If
Else
i += 1
End If
Else
i += 1
End If
End While

In Vb.Net,How to write a .csv file without Carriage Return?

I am working on VS 2012, Vb.Net - .Net 4.0 framework.
My Vb.Net code is reading the .csv file and it is expected to rewrite the file without Carriage Return.
But now, Carriage Return Line Feed is created as a new line in the .csv file.
How to delete CR LF ??
Public Sub Test()
Try
Dim reader As StreamReader = New System.IO.StreamReader(File.OpenRead("D:\CSV\Test.csv"))
Dim listA As New List(Of String)()
If File.Exists("d:\CSV\TestOut.csv") Then
File.Delete("d:\CSV\TestOut.csv")
End If
Dim sw As New StreamWriter("d:\CSV\TestOut.csv")
Dim s As String = String.Empty
While reader.Peek() >= 0
Dim line As String = reader.ReadLine()
Dim values As String() = line.Split(";"c)
listA.Add(values(0))
s = s + line + Chr(10)
End While
reader.Close()
sw.WriteLine(s)
sw.Close()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
I don't see what the listA or the values variables are good for. You don't need them for the CRLF to LF task.
See:
Try
If File.Exists("D:\CSV\Output.csv") Then File.Delete("D:\CSV\Output.csv")
Using reader As New StreamReader(File.OpenRead("D:\CSV\Input.csv"))
Using writer As New StreamWriter("D:\CSV\Output.csv")
Dim strBldr As New Text.StringBuilder
While reader.Peek > -1 ' Seen like this at MSDN page for Peek() function
Dim line = reader.ReadLine
' If you really need the first value of each line, you can still do it here.
strBldr.Append(line).Append(Chr(10))
End While
writer.Write(strBldr.ToString)
End Using
End Using
Catch ex As Exception
MsgBox(ex.Message)
End Try
You should use the Using-Keyword for Streams. When leaving, End Using will close and Dispose() the stream object. It will always do, even if exceptions are thrown or you return a value; just like Finally statements in a Try block.
When you expand a String-Variable often at the end like s = s + line + Chr(10), please consider using a StringBuilder which is optimized for this.
When you need the first and only the first value in the list, line.Split({";"c}, 2) will split the first value and leaves the big rest as one String and not maybe hundreds of String objects just for the garbage collection. Even more appropriate would be using line.Substring(0, line.IndexOf(";")) which doesn't generate a rest at all.

skip first row when reading excel CSV file

I found how to do this in several languages but not in .net (specifically vb.net). I am using OLeDbCommand to read both CSV and Excel files. In case of Excel I can skip first row and select second row onwards by specifying a range of cells. But in case of CSV, I am not sure how to do it.
Current code looks like:
Dim cmd As OleDbCommand = New OleDbCommand("SELECT * FROM [" + Path.GetFileName(FileName) + "]", cn)
Here we give the file, not the sheet. So I am bit stuck.
From my experience reading a text file like this is very restrictive. It only allows you to read the whole file, because you can't specify a table name. You might be better of reading each line and making table rows and adding them to a table. If the first row is headers you can use that to make the columns, otherwise hard code the columns.
Here's a simple little method that fills a datatable with the data from a .csv file, that you should be able to use:
Private Sub GetData(ByRef dt As DataTable, FilePath As String, Optional ByVal Header As Boolean = True)
Dim Fields() As String
Dim Start As Integer = CInt(Header) * -1
If Not File.Exists(FilePath) Then
Return
End If
dt.Clear()
Dim Lines() As String = File.ReadAllLines(FilePath)
If CBool(Start) AndAlso dt.Columns.Count = 0 Then
Lines(0) = Lines(0).Replace(Chr(34), "")
For Each h As String In Lines(0).Split(",")
dt.Columns.Add(h)
Next
End If
For I = Start To Lines.Count - 1
Fields = Lines(I).Split(",")
dt.Rows.Add(Fields)
Next
End Sub

For some reason my program is not reading the file that I asked to be read

You can see thatt I've opened the file just below, but I've recently discovered that It is reading a file open above, which I have closed.
Dim TestNO As Integer
Dim myLines As New List(Of String)
Dim sb As StringBuilder
FileOpen(10, "F:\Computing\Spelling Bee\testtests.csv", OpenMode.Input)
Dim Item() As String = Split(fullline, ",")
Dim MaxVal As Integer = Integer.MaxValue
Do Until EOF(10)
fullline = LineInput(10)
If Item(7) > MaxVal Then
MaxVal = Item(7)
TestNO = MaxVal
End If
Loop
This is where I open and close my previous file.
Dim flag As Boolean = False
FileOpen(1, "F:\Computing\Spelling Bee\stdnt&staffdtls\stdnt&staffdtls.csv",
OpenMode.Input)
Do Until EOF(1)
fullline = LineInput(1)
Dim item() As String = Split(fullline, ",")
If enteredusername = item(0) And enteredpassword = item(1) Then
Console.WriteLine()
Console.Clear()
Console.WriteLine("Welcome," & item(3) & item(4))
Threading.Thread.Sleep(1000)
Console.Clear()
flag = True
If item(2) = "p" Then
FileClose(1)
pupilmenu()
ElseIf item(2) = "s" Then
FileClose(1)
staffmenu()
ElseIf item(2) = "a" Then
FileClose(1)
adminmenu()
FileOpen, EOF, and LineInput are all old VB6-style methods which are provided primarily for backwards compatibility. It would be far preferable to use the new .NET classes provided in the System.IO namespace. For instance, this same task is easily performed line this:
For Each line As String In File.ReadAllLines("F:\Computing\Spelling Bee\stdnt&staffdtls\stdnt&staffdtls.csv")
Dim fields() As String = line.Split(","c)
If (enteredUserName = fields(0)) And (enteredPassword = fields(1)) Then
' ...
End If
Next
Notice that I also used line.Split rather than Split(line), which is also an old VB6-style method. It's better to use the new String.Split method.
The File.ReadAllLines method opens the file, reads the entire contents of the file, closes the file, and then returns all of the data as an array of strings, with each item in the array being one line from the file. This is a very simple way to read an entire file. If it is a particularly large file, however, it would be better to use a FileStream object to read one line at a time.
Also, it's worth mentioning that reading a CSV file yourself can be complicated. They aren't always as simple as simply splitting on commas. For instance, the following is an example of a valid CSV line:
Bill, "Red, White, and Blue", Smith
As you can see, that line only contains three fields, but it contains four commas. Also, the quotation marks should not be considered as part of the value in the second field. The easiest way to read a CSV file is to use the TextFieldParser class, which handles all of those eccentricities.

Overwrite a specific line in a text file using VB.NET

I need to do the following:
Change the line in a text file
[Path] = "c:\this\certain\path\"
with this line
[Path] = "c:\that\other\newer\path\"
These paths will most certainly be different lengths, so I need to either replace what's in the quotes or erase the line completely and enter a new one, but in the same spot, not appended to the end of the document.
This will do the trick
Dim thefile As String = "filepath"
Dim lines() As String = System.IO.File.ReadAllLines("filepath")
lines(number of line you want to replace) = "write what you want to replace here"
System.IO.File.WriteAllLines(filepath, lines)
If you really know exactly how the line you want to replace looks and the file you're reading isn't really big, you could try to just use Replace() to add the new line instead of the old one:
Dim reader As New StreamReader("foo.txt")
Dim writer As New StreamWriter("output.txt")
Dim s = reader.ReadToEnd().Replace("[Path]: C:\oldPath\file.txt", "[Path]: C:\newPath")
writer.Write(s)
One quick way is to use readAllLines and WriteAllLines:
Dim ss() As String
ss = File.ReadAllLines([path])
ss(47) = "c:\that\other\newer\path\"
File.WriteAllLines([path], ss)
If you don't know which line to change, you can search through the array ss for it.
Read the text file into a string, iterate over each line and check if it's in the format:
[Path] = "...." (with regular expressions or simply with string.StartsWith("[Path] = "))
In this loop you should be writing out all other lines and when you are on this [Path] line, print out the modified one.
So in code (sorry, it is in C#):
var reader = File.OpenText("foo.txt");
var writer = new StreamWriter("output.txt");
string line;
while ((line=reader.ReadLine()) != null)
{
if (line.StartsWith("[Path]"))
writer.WriteLine("[Path] = \"c:\\that\\other\\newer\\path\\\"");
else
writer.WriteLine(line);
}
of course, close and dispose the StreamReader and StreamWriter.
Here's the deal: due to the way files are stored on disk, you can't write to one line without also updating every line that follows it.
There are number of ways to do this, and the one most appropriate for your situation will depend on things like the size of the file, are you doing this to a lot of files, where in the file you expect to find this, etc.
But most of the time what I like to do is actually create a copy of the old file... So as I seek through the file looking for the line(s) I need to change, I'm also writing what I've read to a new location. When I find the line, I write out the new information. I then keep seeking through the file until I reach the end at which time I close both streams, delete the original, and rename the new one.
First build a function to give the value of line 'n':
Public Function daValorConfig(ByVal numValor As Long, ByVal nomeFicheiroINI As String) As String
Dim reader As StreamReader = New StreamReader(Application.StartupPath & "\" & nomeFicheiroINI & ".ini")
Dim valor As String = ""
daValorConfig = ""
Dim i As Long = 1
Try
While i <= numValor
valor = reader.ReadLine()
i = i + 1
End While
daValorConfig = valor
reader.Close()
Catch ex As Exception
reader.Close()
MessageBox.Show(ex.Message, "Error: ", MessageBoxButtons.OK, MessageBoxIcon.Error)
Err.Clear()
End Try
End Function
Then build a procedure that writes the new value on the specified line or keep the old one if the line is not the one you specify:
Public Sub guardaValorConfig(ByVal dados As String, ByVal numValor As Long, ByVal nomeFicheiroINI As String)
Dim writer As StreamWriter = New StreamWriter(Application.StartupPath & "\" & nomeFicheiroINI & ".ini")
Dim valor As String = ""
Dim i As Long = 1
Try
While i <= numValor
If i = numValor Then
writer.Write(dados)
Else
writer.Write(daValorConfig(i, nomeFicheiroINI))
End If
i = i + 1
End While
writer.Close()
Catch ex As Exception
MessageBox.Show(ex.Message, "Error: ", MessageBoxButtons.OK, MessageBoxIcon.Error)
Err.Clear()
End Try
End Sub