I want to generate a single SHA256 hash of all the files in a folder in visual basic. I have tried the following code but it generates individual hashes of all files inside the folder, but not a single hash. Can anybody please help.
Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
Dim directory As String
If TextBox2.Text.Length < 1 Then
Dim fdb As New FolderBrowserDialog
Dim dr As DialogResult = fdb.ShowDialog()
If (dr = DialogResult.OK) Then
directory = fdb.SelectedPath
Else
MsgBox("No directory selected")
Return
End If
Else
directory = TextBox2.Text
End If
Try
' Create a DirectoryInfo object representing the specified directory.
Dim dir As New DirectoryInfo(directory)
' Get the FileInfo objects for every file in the directory.
Dim files As FileInfo() = dir.GetFiles()
' Initialize a SHA256 hash object.
Dim mySHA256 As SHA256 = SHA256Managed.Create()
Dim hashValue() As Byte
' Compute and print the hash values for each file in directory.
Dim fInfo As FileInfo
For Each fInfo In files
' Create a fileStream for the file.
Dim fileStream As FileStream = fInfo.Open(FileMode.Open)
' Be sure it's positioned to the beginning of the stream.
fileStream.Position = 0
' Compute the hash of the fileStream.
hashValue = mySHA256.ComputeHash(fileStream)
' Write the name of the file to the Console.
MsgBox(fInfo.Name + ": ")
' Write the hash value to the Console.
PrintByteArray(hashValue)
' Close the file.
fileStream.Close()
Next fInfo
Return
Catch DExc As DirectoryNotFoundException
MsgBox("Error: The directory specified could not be found.")
Catch IOExc As IOException
MsgBox("Error: A file in the directory could not be accessed.")
End Try
End Sub
Public Function PrintByteArray(ByVal array() As Byte)
Dim i As Integer
For i = 0 To array.Length - 1
Label3.Text = (String.Format("{0:X2}", array(i)))
If i Mod 4 = 3 Then
Label3.Text = (" ")
End If
Next i
Return Label3.Text
End Function 'PrintByteArray
You can combine the hashes with XOR to give one 256-bit hash (32 bytes). Because XOR is associative (A XOR B = B XOR A), it does not matter in which order you XOR the file hashes together. You will have to XOR the individual bytes of each hash: Most efficient way to xor byte array in vb.net.
Related
What I'm trying to do:
Open two binary files, each 64 MB
Take first half of each byte of each file and combine those halves in 1 bytes same with second half, for example: first byte in first file is 0x51, in second file its 0xA2, so I need write two bytes in third file which are 0x5A and 0x12, same for whole bytes, therefore final length in third file will be 128 MB.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles
Button1.Click
Try
' choosing first file
OpenFileDialog1.FileName = "First file"
OpenFileDialog1.Title = "Choose the Address.bin file"
OpenFileDialog1.Filter = "bin files (*.bin)|*.bin|All files
(*.*)|*.*"
If OpenFileDialog1.ShowDialog() = Windows.Forms.DialogResult.OK
Then
Label1.Text =
System.IO.Path.GetFullPath(OpenFileDialog1.FileName)
Else
Exit Sub
End If
Catch ex As Exception
End Try
Try ' choosing first file
OpenFileDialog1.FileName = "Second FIle"
OpenFileDialog1.Title = "Choose the Flash.bin file"
OpenFileDialog1.Filter = "bin files (*.bin)|*.bin|All files (*.*)|*.*"
If OpenFileDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then
Label2.Text = System.IO.Path.GetFullPath(OpenFileDialog1.FileName)
Else
Exit Sub
End If
Catch ex As Exception
End Try
Dim firstFileByte(1) As Byte
Dim SecondFileByte(1) As Byte
Dim Result As String
Dim Result2 As String
Dim Final(1) As Byte
For i = 0 To FileLen(Label1.Text) - 1
Using FirstFile As New FileStream(Label1.Text, FileMode.Open) 'save
'FIRST DIGIT********************************************************************************************
FirstFile.Seek(i, SeekOrigin.Begin)
FirstFile.Read(firstFileByte, 0, 1)
'TextBox1.Text = final(0).ToString("X")
Using SecFile As New FileStream(Label2.Text, FileMode.Open) 'save
SecFile.Seek(i, SeekOrigin.Begin)
SecFile.Read(SecondFileByte, 0, 1)
End Using
Result = firstFileByte(0).ToString("X2").Substring(0, 1) & SecondFileByte(0).ToString("X2").Substring(0, 1) ' comobining frist half of the first file and second file
Result2 = firstFileByte(0).ToString("X2").Substring(1, 1) & SecondFileByte(0).ToString("X2").Substring(1, 1) ' comobining second half of the first file and second file
End Using
Using vFs As New FileStream(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) & "\Result.bin", FileMode.Append) ' save
TextBox1.Text = Result2
'Dim FileLenVar As UInt32 = FileLen(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) & "\Result.bin") - 1
Final(0) = Convert.ToByte(Result, 16) 'converting result to the byte
Final(1) = Convert.ToByte(Result2, 16)
vFs.Write(Final, 0, 1)
vFs.Write(Final, 1, 1)
End Using
Next
End Sub
It works, but takes a lot of time: it writes 1 MB in 1 minute. How can I optimize it?
The files are small enough to load into RAM for processing. Processing the data in RAM can minimise the disk I/O needed, the latter very often being the slowest part of a program, especially if it is done in very small pieces like individual bytes. As also noted by Ben Voigt, string operations are somewhat slower than numeric operations.
Here's a simple demonstration of what could be done:
Imports System.IO
Module Module1
Dim f1 As String = "C:\temp\A.bin"
Dim f2 As String = "C:\temp\B.bin"
Dim outFile As String = "C:\temp\C.bin"
Sub CombineFiles()
Dim a1 = File.ReadAllBytes(f1)
Dim a2 = File.ReadAllBytes(f2)
Dim c(a1.Length + a2.Length - 1) As Byte ' c for combined
Dim highBits As Byte = &HF0
Dim lowBits As Byte = &HF
For i = 0 To c.Length - 1 Step 2
c(i) = a1(i \ 2) And highBits Or a2(i \ 2) >> 4
c(i + 1) = a1(i \ 2) << 4 Or a2(i \ 2) And lowBits
Next
File.WriteAllBytes(outFile, c)
End Sub
Sub CreateTestFiles()
'TODO: be more creative with the generated data.
Dim nBytes = 64
Dim a(nBytes - 1) As Byte
For i = 0 To nBytes - 1
a(i) = &H12
Next
File.WriteAllBytes(f1, a)
For i = 0 To nBytes - 1
a(i) = &HAB
Next
File.WriteAllBytes(f2, a)
End Sub
Sub Main()
'CreateTestFiles()
CombineFiles()
End Sub
End Module
Of course, you'd check that the input files were of equal length, and check for any other possible problems ;)
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
I have been trying to combine or pair two text files.
One file contains User:Key
The other file contains Key:Pass
I want a 3rd text file created containing the corresponding pairs of User:Pass based on the key matching.
Here is what Ive tried most recently
Private Sub Rotate()
Dim Cracked() As String = IO.File.ReadAllLines(TextBox1.Text)
For Each lineA In Cracked
TextBox5.Text = lineA
check()
Next
End Sub
Private Sub check()
Dim toCheck() As String = TextBox5.Text.Split(":")
Dim tHash As String = toCheck(0)
Dim tPass As String = toCheck(1)
Dim lines1() As String = IO.File.ReadAllLines(TextBox2.Text)
For Each line In lines1
If lines1.Contains(tHash) Then
Dim toAdd() As String = line.Split(":")
Dim uHash As String = toCheck(0)
Dim uUser As String = toCheck(1)
ListBox1.Items.Add(uUser + ":" + tPass)
End If
Next
End Sub
Public Sub CopyListBoxToClipboard(ByVal ListBox2 As ListBox)
Dim buffer As New StringBuilder
For i As Integer = 0 To ListBox1.Items.Count - 1
buffer.Append(ListBox1.Items(i).ToString)
buffer.Append(vbCrLf)
Next
My.Computer.Clipboard.SetText(buffer.ToString)
End Sub
Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
CopyListBoxToClipboard(ListBox1)
End Sub
The delimiter changes but for now the : works.
I tried splitting and matching but either the textbox5 does not rotate or it rotates through the list and thats all.
Something like this?
Dim KeyPassFile As String = "..."
Dim UserKeyFile As String = "..."
Dim UserPassFile As String = "..."
Dim KeyPass As New Hashtable
' Read Key:Pass file
For Each Line In IO.File.ReadAllLines(KeyPassFile)
Dim iStart = Line.IndexOf(":")
Dim Key = Line.Substring(0, iStart)
Dim Pass = Line.Substring(iStart + 1)
KeyPass.Add(Key, Pass)
Next
' Create User:Pass file
Dim OutFile = IO.File.CreateText(UserPassFile)
' Read User:Key file
For Each Line In IO.File.ReadAllLines(UserKeyFile)
Dim iStart = Line.IndexOf(":")
Dim User = Line.Substring(0, iStart)
Dim Key = Line.Substring(iStart + 1)
If KeyPass.ContainsKey(Key) Then
' We have a match for the key, write it to the file
OutFile.WriteLine(User & ":" & KeyPass(Key))
End If
Next
OutFile.Close()
This will probably not work for very large files that doesn't fit in memory, and there is no duplicate check for the key insertion in the hashtable, but I'll leave something for you to do.. :)
Also, in your code, you read the file specified in the TextBox2.Text as many times as there are lines in the TextBox1.Text file..
i have a listview that shows folders and files, and i can display the size of the files and subfolders, but how do i do it with subfolders only not including the parent/root folder.
EDIT
like, if Folder1's size is 10 MB and it has a SubFolder with 20 MB size with a total of 30 MB, it should only get the size of the SubFolder which is 20 MB when displaying the contents of the Folder1 in a ListView.
Public Shared Function DirSize(ByVal d As DirectoryInfo) As Long
Dim Size As Long = 0
Dim dis As DirectoryInfo() = d.GetDirectories()
Dim di As DirectoryInfo
For Each di In dis
Size += DirSize(di)
Next di
Return Size
End Function
my listview code:
Sub lv1items()
ListView1.Items.Clear()
Dim fPath As String = Form2.TextBox1.Text
Dim di = New DirectoryInfo(fPath)
' store imagelist index for known/found file types
Dim exts As New Dictionary(Of String, Int32)
If di.Exists = False Then
MessageBox.Show("Destination path" & " " & Form2.TextBox1.Text & " is not found.", "Directory Not Found", MessageBoxButtons.OK, MessageBoxIcon.Error)
Form2.Show()
Else
Dim img As Image
Dim lvi As ListViewItem
For Each d In di.EnumerateDirectories("*.*", SearchOption.TopDirectoryOnly)
lvi = New ListViewItem(d.Name)
lvi.SubItems.Add(DirSize(di).ToString("0.00") & " MB")
lvi.SubItems.Add(d.CreationTime.Date)
ListView1.Items.Add(lvi)
img = NativeMethods.GetShellIcon(d.FullName)
ImageList1.Images.Add(img)
lvi.ImageIndex = ImageList1.Images.Count - 1
Next
End Sub
it returns a 0 size folder, but it has a file inside.
a little help please?
You can use this function:
Public Function GetDirectorySize(path As String) As Long
Dim files() As String = Directory.GetFiles(path, "*", SearchOption.AllDirectories)
Dim size As Long = 0
For Each file As String In files
Dim info As New FileInfo(file)
size += info.Length
Next
Return size
End Function
Note that this checks the size of every file in the folder and its subdirectories. Thus it is guaranteed to return the correct size.
Proof that it works:
Root:
SubFolder:
Total Size = (1483 + 25315) * 1024 = 274411152 bytes.
Program Output:
27440016 bytes ≈ 274411152 bytes.
Note: The difference exists because Windows Explorer rounds off some bytes to display the KB. If you view the properties of each file and add up then you will get the same size from both Explorer and the function.
I am saving a .csv file in my directory by giving the path with StreamWriter. Now i want to give the option to user to save that file desired path. how can it. help me somebody.
Dim objStreamWriter = New IO.StreamWriter("c:\FaultTypesByMonth.csv")
Dim Str As String
Dim i As Integer
Dim j As Integer
Dim headertext1(rsTerms.Columns.Count) As String
Dim k As Integer = 0
Dim arrcols As String = Nothing
For Each column As DataColumn In TempTab.Columns
headertext1(k) = column.ColumnName
arrcols += column.ColumnName.ToString() + ","c
k += 1
Next
objStreamWriter.WriteLine(arrcols)
For i = 0 To (TempTab.Rows.Count - 1)
For j = 0 To (TempTab.Columns.Count - 1)
'this IF statement stops it from adding a comma after the last field
If j = (TempTab.Columns.Count - 1) Then
Str = (TempTab.Rows(i)(j).ToString)
Else
Str = (TempTab.Rows(i)(j).ToString & ",")
End If
objStreamWriter.Write(Str)
Next
objStreamWriter.WriteLine()
Next
objStreamWriter.Close()
' After save the file in C:/ I want to save the same file in any other Path for my convenience.
'------------------------------------------------------------------------------------------------
Dim sd As New SaveFileDialog
sd.Filter = "CSV Files (*.csv)|*.csv"
sd.FileName = "FaultTypesByMonth"
If sd.ShowDialog = Windows.Forms.DialogResult.OK Then
'save the file here
Debug.WriteLine("Save file location:" + sd.FileName)
End If
If it's a console application you could read a path argument from the command line.
If it's a GUI application you can show a save file dialog box, in WinForms use the SaveFileDialog class.
To save a file to different locations put the writer code in a function which takes the file path as an argument:
Sub SaveFile(filePath As String)
Dim objStreamWriter = New IO.StreamWriter(filePath)
' ... your code here
End Sub
Sub ButtonClick
SaveFile("c:\FaultTypesByMonth.csv")
' ... SaveFileDialog code
SaveFile(sd.Filename)
End Sub
To copy a file use File.Copy:
' ... SaveFileDialog code
File.Copy("c:\FaultTypesByMonth.csv", sd.Filename)
Use the SaveFileDialog class
Simple example:
Private Sub SaveFile()
Dim sd As New SaveFileDialog
sd.Filter = "CSV Files (*.csv)|*.csv"
If sd.ShowDialog = Windows.Forms.DialogResult.OK Then
'save the file here
Debug.WriteLine("Save file location:" + sd.FileName)
End If
End Sub