VB - If StreamReader reads line containing ("string1") but missing ("string2") - vb.net

EDIT: How would I go about retrieving the filename of the files that meet said conditions?
How I can check if a string contains "value1" but doesn't have "value2"? I tried this:
While Not sr.EndOfStream
Dim sLine As String = sr.ReadLine
If sLine.Contains("value1") Then
If Not sLine.Contains("value2") Then
sw.WriteLine("write name of file that meets conditions to txt file")
End While
Not sure how to go about searching for the missing value.

You could load the whole file in a string and do the check
If wholeFileData.Contains("value1") AndAlso Not wholeFileData.Contains("value2") Then
sw.WriteLine("write name of file that meets conditions to txt file")
End If
If you are need to loop each line, then you'll need to store in a variable and show the message at the end.
Dim containsValue1, containsValue2 As Boolean
containsValue1 = False
containsValue2 = False
While Not sr.EndOfStream
Dim sLine As String = sr.ReadLine
If sLine.Contains("value1") Then
containsValue1 = True
End If
If sLine.Contains("value2") Then
containsValue2 = True
End If
End While
If containsValue1 AndAlso Not containsValue2 Then
sw.WriteLine("write name of file that meets conditions to txt file")
End If

If sLine.Contains("value1") = True and sLine.Contains("value2") = False Then
Msgbox("sLine contains value1, but does not contain value2")
End If

Related

How to search multiple text files in a directory for a string of text at once

I have a ListBox with a certain amount of items in it.
For each item in the ListBox a corresponding text file exists in the file directory.
I need to search each text file (based on what's in the ListBox) for a persons name. Each text file may contain the name or it may not.
I would then like a return which text file contains the name.
I have tried this as a way to search a text file: it works, but I'm not sure how to get this to repeat based on whats in a ListBox.
Dim sFileContents As String = String.Empty
If (System.IO.File.Exists((Application.StartupPath) & "\Project_Green.txt")) Then
sFileContents = (System.IO.File.ReadAllText((Application.StartupPath) & "\Project_Green.txt"))
End If
If sFileContents.Contains(TextBox4.Text) Then
MessageBox.Show("yup")
Else
MessageBox.Show("nope")
End If
Also, if it would be possible to ignore case that would be great.
If you have a bunch of files in a directory and you have their names in a ListBox, and you want to search their contents for something.
One liner query:
Imports System.IO
'...
Sub TheCaller()
Dim dir = My.Application.Info.DirectoryPath
Dim ext = ".txt" ' If the extensions are trimmed in the list.
Dim find = TextBox4.Text
Dim files = Directory.EnumerateFiles(dir).Where(Function(x) ListBox1.Items.Cast(Of String).
Any(Function(y) String.Concat(y, ext).
Equals(Path.GetFileName(x),
StringComparison.InvariantCultureIgnoreCase) AndAlso File.ReadLines(x).
Any(Function(z) z.IndexOf(find, StringComparison.InvariantCultureIgnoreCase) >= 0))).ToList
ListBox2.Items.Clear()
ListBox2.Items.AddRange(files.Select(Function(x) Path.GetFileNameWithoutExtension(x)).ToArray)
End Sub
Or if you prefer the For Each loop:
Sub Caller()
Dim dir = My.Application.Info.DirectoryPath
Dim find = TextBox4.Text
Dim files As New List(Of String)
For Each f As String In ListBox1.Items.Cast(Of String).
Select(Function(x) Path.Combine(dir, $"{x}.txt"))
If File.Exists(f) AndAlso
File.ReadLines(f).Any(Function(x) x.IndexOf(find,
StringComparison.InvariantCultureIgnoreCase) <> -1) Then
files.Add(f)
End If
Next
ListBox2.Items.Clear()
ListBox2.Items.AddRange(files.Select(Function(x) Path.GetFileNameWithoutExtension(x)).ToArray)
End Sub
Either way, the files list contains the matches if any.
Plus a pseudo-parallel async method, for the very heavy-duty name searches.
The Async Function SearchNameInTextFiles returns a named Tuple:
(FileName As String, Index As Integer)
where FileName is the file parsed and Index is the position where the first occurrence of the specified name (theName) was found.
If no matching sub-string is found, the Index value is set to -1.
The caseSensitive parameter allows to specify whether the match should be, well, case sensitive.
You can start the search from a Button.Click async handler (or similar), as shown here.
Imports System.IO
Imports System.Threading.Tasks
Private Async Sub btnSearchFiles_Click(sender As Object, e As EventArgs) Handles btnSearchFiles.Click
Dim filesPath = [Your files path]
Dim theName = textBox4.Text ' $" {textBox4.Text} " to match a whole word
Dim ext As String = ".txt" ' Or String.Empty, if extension is already included
Dim tasks = ListBox1.Items.OfType(Of String).
Select(Function(f) SearchNameInTextFiles(Path.Combine(filesPath, f & ext), theName, False)).ToList()
Await Task.WhenAll(tasks)
Dim results = tasks.Where(Function(t) t.Result.Index >= 0).Select(Function(t) t.Result).ToList()
results.ForEach(Sub(r) Console.WriteLine($"File: {r.FileName}, Position: {r.Index}"))
End Sub
Private Async Function SearchNameInTextFiles(filePath As String, nameToSearch As String, caseSensitive As Boolean) As Task(Of (FileName As String, Index As Integer))
If Not File.Exists(filePath) then Return (filePath, -1)
Using reader As StreamReader = New StreamReader(filePath)
Dim line As String = String.Empty
Dim linesLength As Integer = 0
Dim comparison = If(caseSensitive, StringComparison.CurrentCulture,
StringComparison.CurrentCultureIgnoreCase)
While Not reader.EndOfStream
line = Await reader.ReadLineAsync()
Dim position As Integer = line.IndexOf(nameToSearch, comparison)
If position > 0 Then Return (filePath, linesLength + position)
linesLength += line.Length
End While
Return (filePath, -1)
End Using
End Function
You can do these simple steps for your purpose:
First get all text files in the application's startup directory.
Then iterate over all names in the ListBox and for each one, search in all text files to find the file that contains that name.
To make the process case-insensitive, we first convert names and text file's contents to "lower case" and then compare them. Here is the full code:
Private Sub findTextFile()
'1- Get all text files in the directory
Dim myDirInfo As New IO.DirectoryInfo(Application.StartupPath)
Dim allTextFiles As IO.FileInfo() = myDirInfo.GetFiles("*.txt")
'2- Iterate over all names in the ListBox
For Each name As String In ListBox1.Items
'Open text files one-by-one and find the first text file that contains this name
Dim found As Boolean = False 'Changes to true once the name is found in a text file
Dim containingFile As String = ""
For Each file As IO.FileInfo In allTextFiles
If System.IO.File.ReadAllText(file.FullName).ToLower.Contains(name.ToLower) Then 'compares case-insensitive
found = True
containingFile = file.FullName
Exit For
End If
Next
'Found?
If found Then
MsgBox("The name '" + name + "' found in:" + vbNewLine + containingFile)
Else
MsgBox("The name '" + name + "' does not exist in any text file.")
End If
Next
End Sub

Read line where is specific word in txt file

I need to read the Config file for load settings.
My code:
Dim preferences As FileInfo
preferences = New FileInfo(".\settings.conf")
If preferences.Exists Then
Dim objReader As New System.IO.StreamReader(".\settings.conf")
Dim tmpLine_theme As String
Do While objReader.Peek() <> -1
tmpLine_theme = objReader.ReadLine()
If tmpLine_theme.StartsWith("theme_selected: ") Then
tmpLine_theme = tmpLine_theme.Replace("theme_selected: ", "")
theme_box.Text = tmpLine_theme
MsgBox("Theme:" + tmpLine_theme)
theme_selected_var = tmpLine_theme
Else
MsgBox("Not working")
End If
Loop
This code causes a loop, through which can't go on.
I need to get the specific word, which then removes and retrieves the required data.
If i get you correctly,you are trying to get the line which contains specific word ? It isn't that hard , just a few lines of code :)
Dim readFile as New List(of String)(File.ReadAllLine("path of file"))
For each line in readFile
If line.Contains("theme_selected: ") Then
line.Replace("theme_selected: ","")
MsgBox(line)
End if
Next

Replace Lf with CrLf in files

Is there a low cost way to test the first line in a file for a LF terminator instead of a CRLF?
We receive a lot of files from customers and a few of them send us EOL terminators as LF's instead of CRLF. We're using SSIS to import so I need the row terminators to be the same. (when I open the file in Notepad++ I can see the lines end with LF instead of CRLF)
If I read the first line of a file into a StreamReader ReadLine, the line looks like it doesn't contain any type of terminator. I tested for line.Contains(vbLf) and vbCr and vbCrLf and all came back false.
I think I can read the entire file into memory and test for vbLf but some of the files we receive are pretty large (25MB) and it seems like a huge resource waste just to check the line terminator in the first row. Worst case is I can rewrite every line in every file we receive with a line + System.Environment.NewLine but again that a waste for files that already use CRLF.
EDIT Final Code Below based on the answer from #icemanind (SSIS script task passing in directory variable)
Public Sub Main()
'Gets the directory and a listing of the files and calls the sub
Dim sPath As String
sPath = Dts.Variables("User::DataSourceDir").Value.ToString
Dim sDirectory As String = sPath
Dim dirList As New DirectoryInfo(sDirectory)
Dim fileList As FileInfo() = dirList.GetFiles()
For Each fileName As FileInfo In fileList
ReplaceBadEol(fileName)
Next
Dts.TaskResult = ScriptResults.Success
End Sub
'Temp filename postfix
Private Const fileNamePostFix As String = "_Temp.txt"
'Tests to see if the file has a valid end of line terminator and fixes if it doesn't
Private Sub ReplaceBadEol(currentFileInfo As FileInfo)
Dim fullName As String = currentFileInfo.FullName
If FirstLineEndsWithCrLf(fullName) Then Exit Sub
Dim fileContent As String() = GetFileContent(currentFileInfo.FullName)
Dim pureFileName As String = Path.GetFileNameWithoutExtension(fullName)
Dim newFileName As String = Path.Combine(currentFileInfo.DirectoryName, pureFileName & fileNamePostFix)
File.WriteAllLines(newFileName, fileContent)
currentFileInfo.Delete()
File.Move(newFileName, fullName)
End Sub
'Enum to provide info on the return
Private Enum Terminators
None = 0
CrLf = 1
Lf = 2
Cr = 3
End Enum
'Eol test reads file, advances to the end of the first line and evaluates the value
Private Function GetTerminator(fileName As String, length As Integer) As Terminators
Using sr As New StreamReader(fileName)
sr.BaseStream.Seek(length, SeekOrigin.Begin)
Dim data As Integer = sr.Read()
While data <> -1
If data = 13 Then
data = sr.Read()
If data = 10 Then
Return Terminators.CrLf
End If
Return Terminators.Cr
End If
If data = 10 Then
Return Terminators.Lf
End If
data = sr.Read()
End While
End Using
Return Terminators.None
End Function
'Checks if file is empty, if not check for EOL terminator
Private Function FirstLineEndsWithCrLf(fileName As String) As Boolean
Using reader As New System.IO.StreamReader(fileName)
Dim line As String = reader.ReadLine()
Dim length As Integer = line.Length
Dim fileEmpty As Boolean = String.IsNullOrWhiteSpace(line)
If fileEmpty = True Then
Return True
Else
If GetTerminator(fileName, length) <> 1 Then
Return False
End If
Return True
End If
End Using
End Function
'Reads all lines into String Array
Private Function GetFileContent(fileName As String) As String()
Return File.ReadAllLines(fileName)
End Function
The reason your lines are testing negative for VbCrLf, VbLf and VbCr is because ReadLine strips those. From the StreamReader.ReadLine documentation:
A line is defined as a sequence of characters followed by a line feed ("\n"),
a carriage return ("\r"), or a carriage return immediately followed by a line
feed ("\r\n"). The string that is returned does not contain the terminating
carriage return or line feed.
If you want all the lines, concatenated with a carriage return, try this:
Dim lines As String() = File.ReadAllLines("myfile.txt")
Dim data As String = lines.Aggregate(Function(i, j) i + VbCrLf + j)
This will read in all the lines of your file, then use some Linq to concatenate them all with a carriage return and line feed.
EDIT
If you are looking just to determine what the first line break character is, try this function:
Private Enum Terminators
None = 0
CrLf = 1
Lf = 2
Cr = 3
End Enum
Private Shared Function GetTerminator(fileName As String) As Terminators
Using sr = New StreamReader(fileName)
Dim data As Integer = sr.Read()
While data <> -1
If data = 13 Then
data = sr.Read()
If data = 10 Then
Return Terminators.CrLf
End If
Return Terminators.Cr
End If
If data = 10 Then
Return Terminators.Lf
End If
data = sr.Read()
End While
End Using
Return Terminators.None
End Function
Just call this function, passing in a filename and it will return "Cr", "Lf", "CrLf" or "None" if there are no line terminators.

Parse Log File - Reading from the end first

Having some trouble with a log file I need to parse and display certain fields in a data grid view. The log file is a large tab delimited file and I can read it and parse the array easily. The issue is that I want to start at the END of the file and read backwards until I hit a certain value in one of the fields. Then I want to start reading forward again until it hits the end of the file. While it's reading to the end I want it to fill the data grid view with certain fields. Here's what I have so far -
Looking at the code - it needs to read from the end until the 4th field equals zero and then start reading forward again. I can also read from the end, saving the values to the data grid view as I go until I hit that 0 if that's easier.
Thanks for the help!
The other option would be to read the file and save it in reverse, line by line - the last line first, the 2nd to last line 2nd, etc. That would be really nice as I have another function that will need to read the file and it also needs to go from the end to the beginning.
Private Sub btnParseLog_Click(sender As Object, e As EventArgs) Handles btnParseLog.Click
Dim FileLocation As String = "BLAHBLAHBLAH"
Dim LogFile As String = "LOGFILE"
DataGridView1.ColumnCount = 3
DataGridView1.ColumnHeadersVisible = True
' Set the column header style.
Dim columnHeaderStyle As New DataGridViewCellStyle()
columnHeaderStyle.BackColor = Color.Beige
columnHeaderStyle.Font = New Font("Verdana", 10, FontStyle.Bold)
DataGridView1.ColumnHeadersDefaultCellStyle = columnHeaderStyle
DataGridView1.Columns(0).Name = "User"
DataGridView1.Columns(1).Name = "Number"
DataGridView1.Columns(2).Name = "Time"
Using MyReader As New Microsoft.VisualBasic.FileIO.TextFieldParser(LogFile)
MyReader.TextFieldType =
Microsoft.VisualBasic.FileIO.FieldType.Delimited
MyReader.Delimiters = New String() {vbTab}
Dim TotalLineCount As Integer = File.ReadAllLines(LogFile).Length
Dim currentRow As String()
Dim RowCount As Integer = 0
'Loop through all of the fields in the file.
'If any lines are corrupt, report an error and continue parsing.
While Not MyReader.EndOfData
Try
currentRow = MyReader.ReadFields()
RowCount = RowCount + 1
' Include code here to handle the row.
If RowCount = TotalLineCount Then
While Not currentRow(4).ToString = 0
DataGridView1.Rows.Add(currentRow(1).ToString, currentRow(4).ToString, currentRow(7).ToString)
RowCount = RowCount - 1
End While
End If
Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
MsgBox("Line " & ex.Message &
" is invalid. Skipping")
End Try
End While
End Using
End Sub

vb.net showdialog openfile to string

i'm trying to importe a csv file after creating on the same application, the only probleme is that even if a string matchs a line from the file, comparing them on vb.net dosn't give a true boolean i know i didn't make any mistakes because of the line with the commentary 'THIS LINE , i use a pretty small list to do my test and in that loop, there is always one element that matches exactly the string, but comparing them on vb.net dosn't return a true. the result of this is that just after saving the file to my computer while still having it on my listview1 on the application, i load it to the application again and it duplicates everything
Dim open As New OpenFileDialog
open.Filter = "CSV Files (*.csv*)|*.csv"
If open.ShowDialog = Windows.Forms.DialogResult.OK Then
Dim File As String = My.Computer.FileSystem.ReadAllText(open.FileName)
Dim lines() As String = File.Split(Environment.NewLine)
For i = 1 To (lines.Count - 1)
Dim line As String = lines(i)
Dim Columns() As String = line.Split(";")
Dim addLin As New ListViewItem(Columns)
Dim Alr As Boolean = False
Dim st as string=listView1.Items.Item(k).SubItems.Item(0).Text
For k = 0 To (ListView1.Items.Count - 1)
Dim st as string=listView1.Items.Item(k).SubItems.Item(0).Text
MsgBox(Columns(0)& Environment.NewLine & st) 'THIS LINE
If ListView1.Items.Item(k).SubItems.Item(0).Text = Columns(0) Then
Alr = True
MsgBox("true") 'never showsup even when the previous one show the match
End If
next
If Alr = False Then
MsgBox("false") 'the msgbox is only to check
ListView1.Items.Add(addLin)
End If
next
end if