IOException was unhandled "The process cannot access the file - vb.net

I am trying to reading the file, reformat some rows, then overwrite the file line by line.
I know the problem is cause by opening the existing file twice, but I don't know how to fix it.
Public Sub Main()
Dim objStreamReader As StreamReader
Dim objWriter As StreamWriter
If Dts.Variables("File").Value.ToString.Length > 0 Then
'read the file
objStreamReader = New StreamReader(Dts.Variables("File").Value.ToString)
'write the file
objWriter = New StreamWriter(Dts.Variables("File").Value.ToString)
'read file line by line
Dim row, line As String
Dim isFirstRow As Boolean = True
Dim numColumns As Integer = 0
row = ""
Do While objStreamReader.Peek() <> -1
line = objStreamReader.ReadLine() 'read a line
If line.Trim() = "" Then
Continue Do 'skip blank line
End If
If isFirstRow Then 'first line in the file (it's always a complete row)
numColumns = CountNumColumns(line) 'record the number of columns
isFirstRow = False
objWriter.WriteLine(line)
ElseIf CountNumColumns(line) = numColumns Then
'the line is a complete row
objWriter.WriteLine(line)
Else
row = row & line
If CountNumColumns(row) = numColumns Then
'we have a complete row
objWriter.WriteLine(row)
row = ""
End If
End If
Loop
'close files
objStreamReader.Close()
objWriter.Close()
End If
Dts.TaskResult = ScriptResults.Success
End Sub
'Counts the number of columns in a given line
Function CountNumColumns(ByVal line As String) As Integer
Dim count As Integer = 0
For index As Integer = 0 To line.Length - 1
If line(index) = "|" Then
count = count + 1
End If
Next
Return count
End Function

Related

An unhandled exception of type 'System.IndexOutOfRangeException' occurred in vb.net CSV program

This program is simply reading from a CSV and putting that into a DatagridView table. I am not sure what is causing the error shown below.
"An unhandled exception of type 'System.IndexOutOfRangeException' occurred in Minecraft Server Program.exe"
This error points to the line "newrow("Days_remaining") = columns(1)
Also, the CSV is formatted as such:
xX_EpicGamer_Xx,2,2/05/2021,9,6,Player was mean to others and stole lots of diamonds
pewdiepie,3,2/05/2021,4,2,Player swore
Thank you for any help
Public Sub LoadCSVFile()
'If the Input file cannot be found, then give error message And exit this Subroutine.
If Not File.Exists(BansCSVFile) Then
MsgBox("Input CSV File of Item Prices not found: " & BansCSVFile)
Exit Sub
End If
'Set up streamreader and variables for reading through file
Dim srdCSV As New IO.StreamReader("bans.csv", System.Text.Encoding.Default)
Dim sline As String = ""
Do
'Read through each line, separating with the comma and putting each entry into its respective column
sline = srdCSV.ReadLine
If sline Is Nothing Then Exit Do
Dim columns() As String = sline.Split(",")
Dim newrow As DataRow = datatable1.NewRow
newrow("Player") = columns(0)
newrow("Days_remaining") = columns(1)
newrow("Date_started") = columns(2)
newrow("Timespan") = columns(3)
newrow("Rule_broken") = columns(4)
newrow("Extra_info") = columns(5)
datatable1.Rows.Add(newrow)
Loop
srdCSV.Close()
dgvBans.DataSource = datatable1
Me.Text = datatable1.Rows.Count & "rows"
End Sub
Edit:
This new code fixed the issue.
Public Sub LoadCSVFile()
'If the Input file cannot be found, then give error message And exit this Subroutine.
If Not File.Exists(BansCSVFile) Then
MsgBox("Input CSV File of Item Prices not found: " & BansCSVFile)
Exit Sub
End If
'Set up streamreader and variables for reading through file
srdCSV = New IO.StreamReader("bans.csv")
Dim totalrec As Integer = 0
Try
Do Until srdCSV.Peek = -1
'Read through each line, separating with the comma and putting each entry into its respective column
strInputFileLine = srdCSV.ReadLine()
'Split CSV lines where commas are
Dim RecordLineColumns() As String = strInputFileLine.Split(",")
'Create a new row in data table and place data into it from array
Dim newrow As DataRow = datatable1.NewRow
newrow("Player") = RecordLineColumns(0)
newrow("Days_remaining") = RecordLineColumns(1)
newrow("Date_started") = RecordLineColumns(2)
newrow("Timespan") = RecordLineColumns(3)
newrow("Rule_broken") = RecordLineColumns(4)
newrow("Extra_info") = RecordLineColumns(5)
datatable1.Rows.Add(newrow)
totalrec = totalrec + 1
Loop
Catch ex As Exception
MsgBox("Error reading file")
Exit Sub
End Try
srdCSV.Close()
'Me.Text = datatable1.Rows.Count & "rows"
MsgBox("Total input records = " & totalrec)
End Sub
using the Try/Catch syntax
After checking which column has a problem, try verifying the csv file.
I am guessing that the Extra_Info is not necessarily present for every record. I am checking for a length less 5 and exiting but if it has at least 5 we continue but only fill in the last field if the length is 6.
Public Sub LoadCSVFile(BansCSVFile As String)
Dim datatable1 As New DataTable
With datatable1.Columns
.Add("Player")
.Add("Days_remaing")
.Add("Date_started")
.Add("Timespan")
.Add("Rule_broken")
.Add("Extra_Info")
End With
If Not File.Exists(BansCSVFile) Then
MsgBox("Input CSV File of Item Prices not found: " & BansCSVFile)
Exit Sub
End If
Dim lines = File.ReadAllLines(BansCSVFile)
For Each sline In lines
Dim columns() As String = sline.Split(","c)
If columns.Length < 5 Then
MessageBox.Show($"Incomplete data on line {sline}")
Return
End If
Dim newrow As DataRow = datatable1.NewRow
newrow("Player") = columns(0)
newrow("Days_remaining") = columns(1)
newrow("Date_started") = columns(2)
newrow("Timespan") = columns(3)
newrow("Rule_broken") = columns(4)
If columns.Length = 6 Then
newrow("Extra_info") = columns(5)
End If
datatable1.Rows.Add(newrow)
Next
dgvBans.DataSource = datatable1
Me.Text = datatable1.Rows.Count & "rows"
End Sub

Adding rows to a DataGridView control causes crash but only on second attempt

I have a DataGridView (dgvNew) which is populated by a JSON file which is located by a FileSystemWatcher, data is added row by row after being read. It works fine on first file. But if i trigger a new file by copying and pasting the same JSON file it adds the rows again row by row as id expect, but then the whole form crashes with no error.
I've tried TRY..CATCH with WHILE loops for opened the files which works in terms of openning them and adding rows, i just don't understand why it crashes. The code continues to step through regardless even though the form is frozen ? is it Thread related ?
Public Sub subParseJSONs(strFilePath As String, strDesiredField As String)
Dim json As String
Dim strMachine As String
Dim read As New Newtonsoft.Json.Linq.JObject
Dim booErrorJSNOArrRead As Boolean
Dim i As Integer
Dim dgvIndex As Integer
Dim booOpened As Boolean
Dim k As Integer, j As Integer
booOpened = False
k = 1
j = 1
json = Nothing
While json Is Nothing
Try
j = j + 1
If j = 10 Then
MessageBox.Show("J integer reached 10")
Exit While
Exit Try
End If
json = Replace(Replace(System.IO.File.ReadAllText(strFilePath), vbLf, ""), vbTab, "")
read = Newtonsoft.Json.Linq.JObject.Parse(json)
Catch ex As IOException
'MessageBox.Show(ex.Message)
Threading.Thread.Sleep(300)
'GoTo EndOfSUb
Catch ex As Exception
'MessageBox.Show(ex.Message)
Threading.Thread.Sleep(300)
'GoTo EndOfSUb
Finally
booOpened = True
End Try
End While
booErrorJSNOArrRead = False
i = 0
dgvNew.ColumnCount = 6
dgvNew.Columns(0).Name = "TempID"
dgvNew.Columns(1).Name = "DriverName"
dgvNew.Columns(2).Name = "Seat"
dgvNew.Columns(3).Name = "RaceTime"
dgvNew.Columns(4).Name = "ResultTime"
dgvNew.Columns(5).Name = "CarDriven"
dgvNew.RefreshEdit()
dgvNew.Refresh()
Do Until i = read.Item("Result").Count
If Not read.Item("Result")(i)("DriverName") = "" Then
Dim milliseconds As Double = Convert.ToDouble(read.Item("Result")(i)("TotalTime"))
Dim ts As TimeSpan = TimeSpan.FromMilliseconds(milliseconds)
Dim strMMSSmmm As String = ts.Minutes.ToString & ":" & ts.Seconds.ToString & "." & ts.Milliseconds.ToString
Dim row As String() = New String() {i + 1,
read.Item("Result")(i)("DriverName"),
read.Item("Result")(i)("DriverName"),
strMMSSmmm,
DateTime.Now, read.Item("Result")(i)("CarModel")}
dgvNew.Rows.Add(row)
End If
i = i + 1
Loop
read = Nothing
End Sub
I'm expecting new rows to be added to the bottom of dgvNew, which they are, but then it crashes ?

Backgroundworker not starting copy

I am a novice at VB.NET and am working on an app the read the contents of a text file and use the paths therein for a file/folder copy. I am running the copy through a backgroundworker which does not seem to take the line string. To troubleshoot I have placed a MessageBox.Show(line) under the line reading logic to see if it is reading the path. It is not and jumps straight to my BackgroundWorker1_RunWorkerCompleted sub.
Can anyone see where I am going wrong?!
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As ComponentModel.DoWorkEventArgs, Optional ByVal Overwrite As Boolean = True) Handles BackgroundWorker1.DoWork
Dim deststring As String
' Open config.txt with the Using statement.
Using r As StreamReader = New StreamReader(Application.StartupPath + "\CONFIG.txt")
Dim line As String
' Read first line.
line = r.ReadLine
' Loop over each line in file, While list is Not Nothing.
Do While (Not line Is Nothing)
' Read line and filter based on logic
If line.StartsWith("*") Then
r.ReadLine()
ElseIf line.Contains(Destpath) Then
r.ReadLine()
ElseIf line.Equals("%USERPROFILE%\Desktop") Then
line = desktoppath
ElseIf line.Equals("%USERPROFILE%\Downloads") Then
line = downloadsPath
ElseIf line.Equals("%USERPROFILE%\Contacts") Then
line = contactspath
ElseIf line.Equals("%USERPROFILE%\Documents") Then
line = documentspath
ElseIf line.Equals("%USERPROFILE%\Favorites") Then
line = favoritespath
ElseIf line.Equals("%USERPROFILE%\Links") Then
line = linkspath
ElseIf line.Equals("%USERPROFILE%\Music") Then
line = Musicpath
ElseIf line.Equals("%USERPROFILE%\Pictures") Then
line = picturespath
ElseIf line.Equals("%USERPROFILE%\SavedGames") Then
line = savedgamespath
ElseIf line.Equals("%USERPROFILE%\SavedSearches") Then
line = savedsearchespath
ElseIf line.Equals("%USERPROFILE%\Videos") Then
line = videospath
ElseIf line.Contains("%USERNAME%") Then
line = line.Replace("%USERNAME%", Username)
Else
Console.Writeline(line)
'Read line and create a full path for the destination
Dim SubPath As String = line.Split("\").Last
Dim FullDestPath As String = Destpath & "\" & SubPath
Console.Writeline(FullDestPath)
If Not System.IO.Directory.Exists(FullDestPath) Then
System.IO.Directory.CreateDirectory(FullDestPath)
End If
'Get directory info's
Dim SourceDir As DirectoryInfo = New DirectoryInfo(line)
Dim DestDir As DirectoryInfo = New DirectoryInfo(FullDestPath)
Dim ChildFile As FileInfo
'Loop through each file in the SourceDir
For Each ChildFile In SourceDir.GetFiles()
'Display file being copied
SetLabelText_ThreadSafe(Me.lblStatus, "Copying: " & line & "\" & ChildFile.Name & "")
'Do the copy
ChildFile.CopyTo(Path.Combine(DestDir.FullName, ChildFile.Name), True)
deststring = DestDir.ToString & "\" & ChildFile.Name
Dim sourcedirstring As String
sourcedirstring = SourceDir.ToString & "\" & ChildFile.Name
'Open Stream
Dim CopyStream As New FileStream(sourcedirstring, FileMode.Open, FileAccess.Read)
Dim NewStream As New FileStream(deststring, FileMode.CreateNew)
Dim Buffer(100000) As Byte
Dim BytesRead As Integer
'Try loop for each file
Try
Do
BytesRead = CopyStream.Read(Buffer, 0, Buffer.Length)
NewStream.Write(Buffer, 0, BytesRead)
PercentComplete = (NewStream.Length / CopyStream.Length * 100)
PercentComplete = Decimal.Round((PercentComplete), 2)
If PercentComplete > 100 Then
PercentComplete = "0"
End If
'if the file count is only 1 file then make both progress bars the same so that the current file and total are the same
If filecount = 1 Then
percentage = ((NewStream.Length + filetotalsofarcopied) / Overallsize.ToString * 100)
percentage = Decimal.Round((percentage), 2)
If percentage > 100 Then
percentage = 0
End If
SetLabelText_ThreadSafe(Me.lblTotalProgress, "" & percentage & "%")
Else
Timer6.Start()
percentage2 = ((NewStream.Length + filetotalsofarcopied) / Overallsize.ToString * 100)
percentage2 = Decimal.Round((percentage2), 2)
If percentage2 > 100 Then
percentage2 = 0
End If
SetLabelText_ThreadSafe(Me.lblTotalProgress, "" & percentage2 & "%")
End If
SetLabelText_ThreadSafe(Me.lblCurrentFileProgress, "" & PercentComplete & "%")
Dim time As Long = Label22.Text
'Calculate copy speed
Dim kbps As Double = (NewStream.Length + filetotalsofarcopied) / (time * 1024)
If kbps < 1024 Then
SetLabelText_ThreadSafe(Me.lblCopy, String.Format("Copy Speed: {0:0.00} KB/s", kbps))
Else
SetLabelText_ThreadSafe(Me.lblCopy, String.Format("Copy Speed: {0:0.00} MB/s", kbps / 1024))
End If
Loop Until BytesRead = 0 And PercentComplete = 100
Catch ex As Exception
Finally
CopyStream.Dispose()
NewStream.Dispose()
End Try
'File counter
int3 = int3 + 1
'Calculate data being moved for eta to completion
Dim filetotalbytes As Double = ChildFile.Length
filetotalsofarcopied = filetotalbytes + filetotalsofarcopied
'Check for pending cancel
If BackgroundWorker1.CancellationPending = True Then
BackgroundWorker1.CancelAsync()
Exit Sub
End If
Next
'Loop through Sub directories of SourceDir
Dim SubDir As DirectoryInfo
For Each SubDir In SourceDir.GetDirectories()
CopyDirectory(SubDir.FullName, Path.Combine(DestDir.FullName, SubDir.Name), Overwrite)
Next
End If
' Read in the next line.
line = r.ReadLine
Loop
End Using
End Sub
UPDATE: Included .text file contents:
***DESTINATION***
D:\Test
***Sources***
%USERPROFILE%\Downloads
%USERPROFILE%\Favorites
D:\User Data\Adam\Documents\Test
You should remove the calls to ReadLine inside the first two Ifs and replace them with the Continue Do keyword.
In general it is better to have just one call to ReadLine in your code.
For example you could check for End of Stream using the StreamReader.Peek method.
Finally the If block should be closed after the %USERNAME% check
' removed
' line = r.ReadLine()
Dim line As String
Do While r.Peek <> -1
line = r.ReadLine()
Console.Writeline(line)
If line.StartsWith("*") Then
' Not significant, skip to the next line
Continue Do
ElseIf line.Contains(Destpath) Then
' Not significant, skip to the next line
Continue Do
ElseIf line.Equals("%USERPROFILE%\Desktop") Then
line = desktoppath
ElseIf line.Equals("%USERPROFILE%\Downloads") Then
line = downloadsPath
ElseIf line.Equals("%USERPROFILE%\Contacts") Then
line = contactspath
ElseIf line.Equals("%USERPROFILE%\Documents") Then
line = documentspath
ElseIf line.Equals("%USERPROFILE%\Favorites") Then
line = favoritespath
ElseIf line.Equals("%USERPROFILE%\Links") Then
line = linkspath
ElseIf line.Equals("%USERPROFILE%\Music") Then
line = Musicpath
ElseIf line.Equals("%USERPROFILE%\Pictures") Then
line = picturespath
ElseIf line.Equals("%USERPROFILE%\SavedGames") Then
line = savedgamespath
ElseIf line.Equals("%USERPROFILE%\SavedSearches") Then
line = savedsearchespath
ElseIf line.Equals("%USERPROFILE%\Videos") Then
line = videospath
ElseIf line.Contains("%USERNAME%") Then
line = line.Replace("%USERNAME%", Username)
End If
' Now your line variable should be always correct and
' you can execute your copying logic
......
line = r.ReadLine
Loop

check if each line from a text file startwith certain character

Dim reader As StreamReader = New StreamReader("C:\Users\S160358\Desktop\file.txt")
Do While reader.Peek() > -1
Dim line As String = reader.ReadLine()
If line.EndsWith("PSTAT") Then
Console.WriteLine("Yes")
Console.ReadLine()
Else
Console.WriteLine("No")
Console.ReadLine()
End If
Loop
Sample data
1111111111|22222222222222|3333333333|PSTAT
2222222222|33333333333333|
1111111111|PSTAT
AAAAAAAAAA|DDDDDDDDDDDDDD|FFFFFFFFFF|PSTAT
I am trying to check if any of line not end with certain characters. If it return "No" then it will process a reformatting function. After I run this code, it will return "Yes", and it should return "No" as second row is not end with PSTAT.
If you want to check all the lines, then you can't determine the result until you have checked all the lines (or found a line without the ending):
Dim reader As StreamReader = New StreamReader("C:\Users\S160358\Desktop\file.txt")
Dim anyNo As Boolean = False
Do While reader.Peek() > -1
Dim line As String = reader.ReadLine()
If Not line.EndsWith("PSTAT") Then
anyNo = True
Exit Do
End If
Loop
If anyNo Then
Console.WriteLine("No")
Else
Console.WriteLine("Yes")
End If
Console.ReadLine()
Or simply:
Dim anyNo As Boolean = _
File.ReadAllLines("C:\Users\S160358\Desktop\file.txt") _
.Any(Function(line) Not line.EndsWith("PSTAT"))
If anyNo Then
Console.WriteLine("No")
Else
Console.WriteLine("Yes")
End If
Console.ReadLine()

How to Update CSV file not to Insert new Items using vb.net

I want to Update row of CSV file I tried but I only found append which adds new row. where as I need to update row not to insert new row.
Here is data in my csv file
EnjoyBaseHid=hid://002AB1E3,MinID=1,MaxID=900
EnjoyBaseHid=hid://005AC1D4,MinID=1,MaxID=600
I want to update according to EnjoyBaseHid
While Not sr.EndOfStream
Dim line = sr.ReadLine()
Dim values() As String = line.Split(",")
If values(0).Equals("EnjoyBaseHid=" & portAddress) Then
Nobasefound = False
line = line.Replace(values(1), "MinID=" & minID)
line = line.Replace(values(2), "MaxID=" & maxID)
sr.Close()
Dim strWrite As New IO.StreamWriter(ExportListPathString, False)
strWrite.WriteLine(line)
strWrite.Close()
Exit While
End If
End While
This overwrites all file and the result is
EnjoyBaseHid=hid://005AC1D4,MinID=1,MaxID=1000
When I change following line
Dim strWrite As New IO.StreamWriter(ExportListPathString, False)
To this
Dim strWrite As New IO.StreamWriter(ExportListPathString, True)
It appends new line and result is following
EnjoyBaseHid=hid://002AB1E3,MinID=1,MaxID=900
EnjoyBaseHid=hid://005AC1D4,MinID=1,MaxID=600
EnjoyBaseHid=hid://005AC1D4,MinID=1,MaxID=1000
But I need this
EnjoyBaseHid=hid://002AB1E3,MinID=1,MaxID=900
EnjoyBaseHid=hid://005AC1D4,MinID=1,MaxID=1000
This is the idea I had in mind.
Private Sub fileHandler(sourceFile As String, portAddress As String, newMin As String, newMax As String)
Dim tempOutFileName As String = String.Concat(sourceFile, "_tmp")
Dim oldFileName As String = String.Concat(sourceFile, "_old")
'clear away temp file
If File.Exists(tempOutFileName) Then
File.Delete(tempOutFileName)
End If
'clear away old file
If File.Exists(oldFileName) Then
File.Delete(oldFileName)
End If
'open writer for new temp file
Using sw As StreamWriter = New StreamWriter(tempOutFileName, True)
'open reader for source file
Using sr As StreamReader = New StreamReader(sourceFile)
Do While sr.Peek <> -1
Dim line As String = sr.ReadLine
'check if the line read is the one you want to change
If line.Contains(portAddress) Then
'write your NEW line
sw.WriteLine(String.Concat(portAddress, "-", newMin, "-", newMax))
Else
'write the existing line without changes
sw.WriteLine(line)
End If
Loop
sr.Close()
End Using
sw.Close()
End Using
'backup source to old
File.Move(sourceFile, oldFileName)
'move temp to source
File.Move(tempOutFileName, sourceFile)
End Sub