How to read duplicate string in a text file in vb.net - vb.net

I want this program to open a text file and find those specific character and add the words after that into the list (each character has specific subitem in the list).
It work well if there is no duplication. But if I have list like:
/* First row of the list */
#Alireza
%Human
&1
#$1200
$*1
*$1000
/* ' Second row */
#Behzad
%Human
&1
#$1340
$*1
*$1000
/* ' And third row */
#Samaneh
%Human
&1
#$1570
$*1
*$1230
then it only add the first row. I also make a while loop but it will only add first row to other rows. Is there anyone can help please!(by the way my list include 6 columns )
this is the code:
Public code As String
Public cat As String
Public stock As Integer
Public price As Double
Public sold As Double
Public cost As Double
Public i As Integer
Public Sub _Load(ByVal FileName As String)
Dim strLines() As String
Dim strLine As String
Dim strData As String
Dim objFileInfo As New FileInfo(FileName)
strData = My.Computer.FileSystem.ReadAllText(FileName)
strLines = strData.Split(New String() {ControlChars.CrLf}, StringSplitOptions.RemoveEmptyEntries)
For Each strLine In strLines
If strLine.StartsWith("#") Then
code = strLine.Substring(1)
End If
strLine = Nothing
Next
For Each strLine In strLines
If strLine.StartsWith("%") Then
cat = strLine.Substring(1)
Exit For
End If
strLine = Nothing
Next
For Each strLine In strLines
If strLine.StartsWith("&") Then
stock = strLine.Substring(1)
Exit For
End If
strLine = Nothing
Next
For Each strLine In strLines
If strLine.StartsWith("#$") Then
price = strLine.Substring(2)
Exit For
End If
strLine = Nothing
Next
For Each strLine In strLines
If strLine.StartsWith("$*") Then
sold = strLine.Substring(2)
Exit For
End If
strLine = Nothing
Next
For Each strLine In strLines
If strLine.StartsWith("*$") Then
cost = strLine.Substring(2)
Exit For
End If
strLine = Nothing
Next
End Sub
Private Sub button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles toolImport.Click
Dim ans As String
OpenFileDialog1.Title = "What are you looking for?"
OpenFileDialog1.InitialDirectory = Application.StartupPath
OpenFileDialog1.Filter = "text Files (*.txt)|*.txt|Data Files (*.dat)|*.dat|All files (*.*)|*.*"
OpenFileDialog1.FileName = "myList"
Try
If OpenFileDialog1.ShowDialog = Windows.Forms.DialogResult.OK Then
Dim sr As StreamReader = New StreamReader(OpenFileDialog1.FileName)
Do While sr.Peek > -1
_Load(OpenFileDialog1.FileName)
Dim list As New ListViewItem(code)
list.SubItems.Add(cat)
list.SubItems.Add(stock)
list.SubItems.Add(price)
list.SubItems.Add(sold)
list.SubItems.Add(cost)
listClothes.Items.Add(list)
i += 1
MessageBox.Show("Your list has been uploaded successfully", "ccc!", MessageBoxButtons.OK, MessageBoxIcon.Information)
Loop
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub

By "duplicate strings", I think you mean how to read the file when there is more than one item (group of 6 columns) in the file.
The reason your current program is getting only the first item is because you're exiting the For loop after you find the first occurrence of a given sub item, regardless of how many there may be in the file.
One way to resolve this is to change your sub _Load to a function and have it return a List(Of ListViewItem) object, which you could then iterate through and add to the master list (ListClothes). I would also get rid of the StreamReader, as you don't need it for what you are doing. You're passing the FileName property (which contains the path and extensions) from the OpenFileDialog, so you can simply use that in the _Load function.
It would look something like this:
Public Function _Load(ByVal FileName As String) As List(Of ListViewItem)
Dim Lines() As String
Dim List(Of ListViewItem) StockList = New List(Of ListViewItem)
Dim ListViewItem As StockItem
Lines = File.ReadAllText(FileName).Split(New String() _
{ ControlChars.CrLf}, StringSplitOptions.RemoveEmptyEntries)
For j = 0 To Lines.Length - 1 Step 6
StockItem = New ListViewItem(Lines(j))
StockItem.SubItems.Add(Lines(j + 1))
StockItem.SubItems.Add(Lines(J + 2))
StockItem.SubItems.Add(Lines(j + 3))
StockItem.SubItems.Add(Lines(J + 4))
StockItem.SubItems.Add(Lines(j + 5))
StockList.Add(StockItem)
Next
Return StockList
End Function
The above code takes the passed in FileName, does a split on the string returned from ReadAllText and removes empty entries.
Next it loops through code, 6 lines at a time. In the loop a new ListViewItem is created, and the sub items are populated, and then this ListViewItem is added to the List(Of ListViewItem).
The populated StockList is then returned.
In your button1_Click event, you could use it like this:
Private Sub button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles toolImport.Click
Dim ans As String
Dim stockItems As List(Of ListViewItem)
OpenFileDialog1.Title = "What are you looking for?"
OpenFileDialog1.InitialDirectory = Application.StartupPath
OpenFileDialog1.Filter = "text Files (*.txt)|*.txt|Data Files (*.dat)|*.dat|All files (*.*)|*.*"
OpenFileDialog1.FileName = "myList"
Try
If OpenFileDialog1.ShowDialog = Windows.Forms.DialogResult.OK Then
stockItems = _Load(OpenFileDialog1.FileName)
For Each (stockItem As ListViewItem in stockItems)
listClothes.Add(stockItem)
Next
MessageBox.Show("Your list has been uploaded successfully", "ccc!", MessageBoxButtons.OK, MessageBoxIcon.Information)
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
In this code, you pass the selected FileName to the _Load method and assign its return value to the local stockItems variable.
Then you loop through the stockItems list, and add each ListViewItem in it to your clothesList.
NOTE that this code is brittle - if the columns are not in the correct order in the input file, or if a column(s) is/are missing, your data will be skewed, and the program could potentially crash if you try to read a line in the array (from the file) that doesn't exist. Of course, you can wrap that code in a Try Catch block as well.
This is merely one way to do it - I have no doubt there are others. But this should at least get you going in the right direction.
EDIT
The easiest way to remove the leading characters is to add them to the split, like this:
Lines = File.ReadAllText(FileName).Split(New String() _
{ ControlChars.CrLf, "#", "%", "&", "#$", "$*", "*$"}, _
StringSplitOptions.RemoveEmptyEntries)
This will return an array of all the lines, minus empty lines and the leading characters.
Of course, with the code above, you actually don't need those leading characters anymore, as long as the input file always has the columns in the same order.

Related

Index was outside the bounds of the array. VB.NET

My problem
Index was outside the bounds of the array. when i try to run the code , it generates this error
i have two forms : SIGN IN and SIGN UP , my problem is they don't work together and generates the error attached below
Dim fs As New FileStream("C:\Users\Selmen\Desktop\vb\logs.txt", FileMode.Open, FileAccess.ReadWrite)
Dim sr As New StreamReader(fs)
Dim sw As New StreamWriter(fs)
Dim s As String
Dim t() As String
Dim trouve As Integer = 0
Dim tt() As String
Dim ch As String
ch = TextBox1.Text + "#" + TextBox2.Text + "#" + TextBox3.Text + "#" + TextBox4.Text + "#" + TextBox5.Text
tt = ch.Split("#")
Do While (trouve = 0) And (sr.Peek > -1)
s = sr.ReadLine
t = s.Split("#")
If String.Compare(t(2), tt(2)) = 0 Then
trouve = 1
End If
Loop
If (trouve = 1) Then
MsgBox("user existant")
Else
sw.WriteLine(ch)
Me.Hide()
Form4.Show()
End If
sw.Close()
sr.Close()
fs.Close()
End Sub
If String.Compare(t(2), tt(2)) = 0 Then I get:
IndexOutOfRangeException was unhandled / Index was outside the bounds of the array.
Streams need to be disposed. Instead of using streams you can easily access a text file with the .net File class.
File.ReadAllLines returns an array of lines in the file. We can loop through the lines in a For Each. The lower case c following the "#" tells the compiler that you intend a Char not a String. String.Split expects a Char. Normally, String.Compare is used to order strings in alphabetical order. You just need an =. As soon as we find a match we exit the loop with Exit For.
We don't actually need the array of the text boxes Text property unless there is no match. Putting the elements in braces intializes and fills the array of String.
File.AppendAllLines does what it says. It is expecting an array of strings. As with the text boxes, we put our line to append in braces.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim p = "path to file"
Dim lines = File.ReadAllLines(p)
Dim trouve As Integer
For Each line In lines
Dim thirdField = line.Split("#"c)(2)
If thirdField = TextBox3.Text Then
trouve = 1
Exit For
End If
Next
If trouve = 1 Then
MsgBox("user existant")
Else
Dim tt = {TextBox1.Text, TextBox2.Text, TextBox3.Text, TextBox4.Text, TextBox5.Text}
File.AppendAllLines(p, {String.Join("#", tt)})
Me.Hid3e()
Form4.Show()
End If
End Sub

How to check instantly the changes made by user in TextBoxs?

The procedure allows the modification of text zones by means of an Modify button on the main form. Using a structure, I read and store lines from a text file, and populated according to line number, 3 text boxes. On the other hand, in order to leave it to the user to modify something in these zones if necessary, I would need to know which text zones have been modified! Claude.
Here is my code:
Private Sub Button9_Click(sender As Object, e As EventArgs) Handles Button9.Click
' Modifier
Dim bibliotheque As New article
With bibliotheque
.Title = TextBox1.Text
.Name = TextBox2.Text
.Charge = TextBox3.Text
End With
Dim fileName As String = "c:\essai.librairie"
Dim someString As String = Trim(TextBox2.Text)
Dim lignes As String() = File.ReadAllLines(fileName, Encoding.UTF8)
Dim found As Integer = -1
For i As Integer = 0 To lignes.Length - 1
If lignes(i).Contains(someString) Then
found = i
Exit For
End If
Next
Dim lines As String() = File.ReadAllLines("c:\essai.librairie", Encoding.UTF8)
lines(found) = bibliotheque.Title.PadRight(17, " "c).ToString & bibliotheque.Name.PadRight(90, " "c).ToString & bibliotheque.Charge.PadRight(120, " "c).ToString
MessageBox.Show("Enregistrer les données modifiées ?",
"Prénommer", MessageBoxButtons.OKCancel,
MessageBoxIcon.Question, MessageBoxDefaultButton.Button2)
If Windows.Forms.DialogResult.OK Then
File.WriteAllLines("c:\essai.librairie", lines, Encoding.UTF8)
Using fStream As New FileStream("c:\essai.librairie", FileMode.Open, FileAccess.ReadWrite, FileShare.None)
fStream.SetLength(fStream.Length - Environment.NewLine.Length)
End Using
Else
Exit Sub
End If
End Sub
You can use the events txtbox1.changed or txtbox1.leave to take action or flag that textbox as being changed. The .changed event fires every time a character is changed. .leave only fires when focus leaves the text box.

How to combine all csv files from the same folder into one data

I want merge multiple csv files with same layout from the same folder
example :
csv1.csv
ID, PINA,PINB,PCS
1,100,200,450
2,99,285,300
csv2.csv
ID, PINA,PINB,PCS
1,100,200,999
2,99,285,998
out.csv (The file I want make by VB.net)
ID, PINA,PINB,PCS,PCS
1,100,200,450,999
2,99,285,300,998
my problem code :
Dim FileReader As StreamReader
Dim i As Integer = 0
Dim temp As String
For i = 0 To LstFiles.Items.Count - 1
FileReader = File.OpenText(LstFiles.Items.Item(i))
temp = FileReader.ReadToEnd
File.AppendAllText(SaveFileDialog1.FileName, temp)
Next
Please guide me.
Thanks a lot !
Looks to me like each line in the input files has an identifier based on the first value in that row. You want to combine all the numbers after that identifier, from all the files in your ListBox, into one list of numbers that is sorted and has no duplicates. Then you want to generate an output file that has all those identifiers followed by each set of sorted, unique numbers.
If that is correct, then try this out:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If SaveFileDialog1.ShowDialog = DialogResult.OK Then
Dim header As String = ""
Dim combinedLines As New SortedList(Of Integer, List(Of Integer))
For Each filename As String In LstFiles.Items
Dim lines = File.ReadLines(filename)
If header = "" Then
header = lines.First
End If
lines = lines.Skip(1)
For Each line As String In lines
Dim strValues = line.Split(",").AsEnumerable
Try
Dim lineNumber As Integer = Integer.Parse(strValues.First)
strValues = strValues.Skip(1)
Dim numbers = strValues.ToList.ConvertAll(Of Integer)(Function(x) Integer.Parse(x))
If Not combinedLines.ContainsKey(lineNumber) Then
combinedLines.Add(lineNumber, New List(Of Integer)(numbers))
Else
combinedLines(lineNumber).AddRange(numbers)
End If
Catch ex As Exception
MessageBox.Show("Error Parsing Line: " & line)
End Try
Next
Next
Using sw As New StreamWriter(SaveFileDialog1.FileName, False)
sw.WriteLine(header)
For Each numberSet In combinedLines
Dim numbers = numberSet.Value.Distinct.ToList
numbers.Sort()
sw.WriteLine(numberSet.Key & "," & String.Join(",", numbers))
Next
End Using
End If
End Sub

Loop through the lines of a text file in VB.NET

I have a text file with some lines of text in it.
I want to loop through each line until an item that I want is found*, then display it on the screen, in the form of a label.
*I am searching for the item through a textbox.
That is, in sudo:
For i = 0 To number of lines in text file
If txtsearch.text = row(i).text Then
lbl1.text = row(i).text
Next i
You can use the File.ReadLines Method in order to iterate throughout your file, one line at a time. Here is a simple example:
Dim Term As String = "Your term"
For Each Line As String In File.ReadLines("Your file path")
If Line.Contains(Term) = True Then
' Do something...Print the line
Exit For
End If
Next
Here's a function that will spit back your string from the row that contains your search term...
Public Shared Function SearchFile(ByVal strFilePath As String, ByVal strSearchTerm As String) As String
Dim sr As StreamReader = New StreamReader(strFilePath)
Dim strLine As String = String.Empty
Try
Do While sr.Peek() >= 0
strLine = String.Empty
strLine = sr.ReadLine
If strLine.Contains(strSearchTerm) Then
sr.Close()
Exit Do
End If
Loop
Return strLine
Catch ex As Exception
Return String.Empty
End Try
End Function
To use the function you can do this...
Dim strText As String = SearchFile(FileName, SearchTerm)
If strText <> String.Empty Then
Label1.Text = strText
End If
LOOPING AND GETTING ALL XML FILES FROM DIRECTORY IF WE WANT TEXTFILES PUT "*.txt" IN THE PLACE OF "*xml"
Dim Directory As New IO.DirectoryInfo(Path)
Dim allFiles As IO.FileInfo() = Directory.GetFiles("*.xml")
allFiles = allFiles.OrderByDescending(Function(x) x.FullName).ToArray()
Dim singleFile As IO.FileInfo
For Each singleFile In allFiles
'ds.ReadXml(singleFile)
xd.Load(singleFile.FullName)
Dim nodes As XmlNodeList = xd.DocumentElement.SelectNodes("/ORDER/ORDER_HEADER")
Dim ORDER_NO As String = " "
For Each node As XmlNode In nodes
If Not node.SelectSingleNode("ORDER_NO") Is Nothing Then
ORDER_NO = node.SelectSingleNode("ORDER_NO").InnerText
End If
Next
Next

How to replace multiple consective lines in a line and skip the header for that section

I need to find a section header, in this case "[Store Hours]", in a text file that I'm using to save the settings for the program. I need to skip the header and replace the next 7 lines with the text that is in the text boxes. The code below currently deletes the header "[Store Hours]" and does not replace any of the lines.
Dim objFileName As String = "Settings.txt"
Private Sub BtnAdd_Click(sender As System.Object, e As System.EventArgs) Handles btnSaveHours.Click
Dim OutPutLine As New List(Of String)()
Dim matchFound As Boolean
For Each line As String In System.IO.File.ReadAllLines(objFileName)
matchFound = line.Contains("[Store Hours]")
If matchFound Then
'does not skip the header line
line.Skip(line.Length)
'Need to loop through this 7 times (for each day of the week)
'without reading the header again
For intCount = 0 To 6
Dim aryLabelDay() As String = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}
Dim varLabelNameIn As String = "txt" & aryLabelDay(intCount).ToString & "In"
Dim varDropNameIn As String = "drp" & aryLabelDay(intCount).ToString & "In"
Dim varLabelNameOut As String = "txt" & aryLabelDay(intCount).ToString & "Out"
Dim varDropNameOut As String = "drp" & aryLabelDay(intCount).ToString & "Out"
Dim varTextBoxInControl() As Control = Me.Controls.Find(varLabelNameIn, True)
Dim varDropBoxInControl() As Control = Me.Controls.Find(varDropNameIn, True)
Dim varTextBoxOutControl() As Control = Me.Controls.Find(varLabelNameOut, True)
Dim varDropBoxOutControl() As Control = Me.Controls.Find(varDropNameOut, True)
Dim dymTextNameIn As TextBox = DirectCast(varTextBoxInControl(0), TextBox)
Dim dymDropNameIn As ComboBox = DirectCast(varDropBoxInControl(0), ComboBox)
Dim dymTextNameOut As TextBox = DirectCast(varTextBoxOutControl(0), TextBox)
Dim dymDropNameOut As ComboBox = DirectCast(varDropBoxOutControl(0), ComboBox)
Dim ReplaceLine As String
ReplaceLine = dymTextNameIn.Text & "," & dymDropNameIn.Text & "," & dymTextNameOut.Text & "," & dymDropNameOut.Text
'this doesn't replace anything
line.Replace(line, ReplaceLine)
intCount += 1
Next intCount
Else
OutPutLine.Add(line)
End If
Next
End Sub
Instead of using ReadAllLines simply use a streamreader and read the file line by line, like this;
Dim line As String
Using reader As StreamReader = New StreamReader("file.txt")
' Read one line from file
line = reader.ReadLine
If(line.Contains("[Store Hours]") Then
'The current line is the store hours header, so we skip it (read the next line)
line = reader.ReadLine
'Process the line like you want, and keep processing through the lines by doing a readline each time you want to progress to the next line.
End If
End Using
More importantly though, you should not be saving the settings for your program in a text file. They should be stored in app.config or web.config. See this question for further guidance on that.
Part of your confusion might be coming from the fact that you can't just replace part of a text file without copying it and overwriting it. One way, to do this, is to copy the file to memory changing the appropriate lines and overwriting the existing file with the new information. Here's one way that can be done:
Private Sub BtnAdd_Click(sender As System.Object, e As System.EventArgs) Handles btnSaveHours.Click
Dim OutPutLine As New List(Of String)()
Dim sr As New StreamReader(objFileName)
While Not sr.EndOfStream
Dim line = sr.ReadLine
'Found the header so let's save that line to memory and add all the other _
info after it.
If line.Contains("[Store Hours]") Then
OutPutLine.Add(line)
'Need to loop through this 7 times (for each day of the week)
'without reading the header again
Dim aryLabelDay() As String = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}
For intCount = 0 To 6
'even though we're not using the info from the file, calling _
Readline advances the file pointer so that the next iteration _
of the while loop we can finish reading the file.
If Not sr.EndOfStream Then
line = sr.ReadLine
Dim dymTextNameIn As TextBox = DirectCast(Me.Controls("txt" & aryLabelDay(intCount) & "In"), TextBox)
Dim dymDropNameIn As ComboBox = DirectCast(Me.Controls("drp" & aryLabelDay(intCount) & "In"), ComboBox)
Dim dymTextNameOut As TextBox = DirectCast(Me.Controls("txt" & aryLabelDay(intCount) & "Out"), TextBox)
Dim dymDropNameOut As ComboBox = DirectCast(Me.Controls("drp" & aryLabelDay(intCount) & "Out"), ComboBox)
OutPutLine.Add(dymTextNameIn.Text & "," & dymDropNameIn.Text & "," & dymTextNameOut.Text & "," & dymDropNameOut.Text)
End If
Next
Else
'Any line that isn't in that section gets copied as is.
OutPutLine.Add(line)
End If
End While
'Copy all the new info to the same file overwriting the old info.
File.WriteAllLines(objFileName, OutPutLine)
End Sub
On a side note. The Controls collection is indexed by number or name which makes it fairly simple to access the appropriate control just by knowing its name.
Thanks for the help I actually figured it out and this is the final code I used
Private Sub btnSaveHours_Click(sender As System.Object, e As System.EventArgs) Handles btnSaveHours.Click
Dim intOutPutLine As New List(Of String)()
Dim blnSearchString As Boolean
Dim intLineCount As Integer = -1
Dim intLoopCount As Integer
For Each line As String In System.IO.File.ReadAllLines(objFileName)
blnSearchString = line.Contains("[Store Hours]")
If blnSearchString Then
intLineCount = intOutPutLine.Count
line.Remove(0)
intLoopCount = 0
ElseIf intLineCount = intOutPutLine.Count And intLoopCount < 7 Then
line.Length.ToString()
line.Remove(0)
intLoopCount += 1
Else
intOutPutLine.Add(line)
End If
Next
System.IO.File.WriteAllLines(objFileName, intOutPutLine.ToArray())
Dim objFileWrite As New StreamWriter(objFileName, True)
If File.Exists(objFileName) Then
objFileWrite.WriteLine("[Store Hours]")
Dim varMe As Control = Me
Call subConvertFrom12to24Hours(objFileWrite, varMe)
Else
objFileWrite.WriteLine("[Store Hours]")
Dim varMe As Control = Me
Call subConvertFrom12to24Hours(objFileWrite, varMe)
End If
Call btnClear_Click(sender, e)
End Sub