VB.Net Sort files by creation date and get file size - vb.net

I would like to add up the file sizes in a directory starting from the oldest file and second oldest and third and so on, and stop adding when it reaches 10mb and add the file names that were added before 10mb to a list of string.
Here is what I have for now,
Dim filesize as long
Dim folderlist = New List(Of FileInfo)
Dim oldestFile =allFiles.OrderBy(Function(fi) fi.CreationTime).First 
For Each File In allFiles
filesize = File.Length
                            totalfilesize = totalfilesize + filesize
If totalfilesize \< "10000000" Then
folderlst.Add(File)
filecount.Add(File.Name.ToString)
End If
Next

Related

Move binary data until specific values from one file to another

I writing a Visual Basic app and stuck at one point:
I need that app read the file, select everything before DDS string, cut it from file and paste to new file.
Then after edit a DDS insert that header.
Problem is, this header before DDS have not fixed length: every file of this type have different header. I tried to mess with System.IO.FileStream but got no result.
Is this even possible to do?
The header length is not that much, a simple search pattern is probably enough.
Pass the sequence of Bytes to find inside the File and the File path to the FindHeader method.
It returns a byte array containing all the bytes collected before the specified sequence is found.
This is a simple patter matching that seeks forward until it finds the first byte that can match the specified sequence.
It then reads a buffer and compares the buffer with the sequence:
- if it's a match, returns the bytes accumulated until that point;
- if it's not, it backtracks from the current position of a [Sequence Length] - 1 positions (inside the current Stream buffer) and continues.
You can call it like this:
Dim closeSequence = New Byte() { &H44, &H44, &H53 }
Dim headerBytes = FindHeader([Source File 1 Path], closeSequence)
Now we have the Header of the first source file.
The data section of the second source file is then:
Dim sourceFile2DataStart = FindHeader([Source File 2 Path], closeSequence).Length + closeSequence.Length
Dim dataLength = New FileInfo([Source File 2 Path]).Length - sourceFile2DataStart
We need to create a third file which will contain the Header of the fist file and the data read from the second file.
' Create a read buffer. The buffer length is less than or equal to the data length
Dim bufferLength As Integer = CInt(If(dataLength >= 1024, 1024, dataLength))
Dim buffer As Byte() = New Byte(bufferLength - 1) {}
Dim read As Integer = 0
Using two FileStream objects, we create a new Destination File, write the header of the first Source File, the closeSequence that identifies the start of the data section, then we read a buffer from the second Source File and write the buffer to the Destination File:
Dim patchworkFilePath as string = [Path of the Destination File]
Using sWriter As FileStream = New FileStream(patchworkFilePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None),
sReader As FileStream = New FileStream([Source File 2 Path], FileMode.Open, FileAccess.Read, FileShare.None)
sReader.Seek(sourceFile2DataStart, SeekOrigin.Begin)
sWriter.Write(header1Bytes, 0, header1Bytes.Length)
sWriter.Write(closeSequence, 0, closeSequence.Length)
While True
read = sReader.Read(buffer, 0, buffer.Length)
If read = 0 Then Exit While
sWriter.Write(buffer, 0, read)
End While
End Using
The Header reader method:
Public Function FindHeader(filePath As String, headerClosure As Byte()) As Byte()
Dim byteToFind = headerClosure(0)
Dim buffer = New Byte(headerClosure.Length - 1) {}
Dim header = New List(Of Byte)(2048)
Dim read As Integer = 0
Using fs As FileStream = New FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None)
While fs.Position <= (fs.Length - headerClosure.Length)
read = fs.ReadByte()
If read = byteToFind Then
fs.Read(buffer, 1, buffer.Length - 1)
buffer(0) = CByte(read)
If buffer.SequenceEqual(headerClosure) Then Exit While
fs.Seek(-(buffer.Length - 1), SeekOrigin.Current)
End If
header.Add(CByte(read))
End While
End Using
Return header.ToArray()
End Function

How to find total size of files in ReadOnlyCollection(Of String)

I have the below code that collects certain files in a directory and places them in a collection of string. I would like to find the total size of all files in that collection. I have tried .Length, however it says that Length is not a member of Collection(Of String). I have also tried working with FileInfo, however, it doesn't seem to work for what I need. Ultimately, I want to display the total size in a messagebox.
Dim counter = My.Computer.FileSystem.GetFiles(TextBox1.Text,
FileIO.SearchOption.SearchAllSubDirectories, "*.mp4", "*.jpg", "*.wav", "*.pf_import")
Here is an example of one attempt, however it gives me the value of 42, when the true value is 16.5MB.
Dim fi As String
For Each fi In counter
FileLen += fi.Length
I also tried this example, however, it gives me 0.
Dim fi As String
Dim filesize As Integer
For Each fi In counter
FileLen += filesize
Can someone give me an idea of what I'm doing wrong?
Iterate through each file and call the GetFileInfo function and retrieve the Length property which is the size in bytes:
Dim length As Integer = 0
For Each f In My.Computer.FileSystem.GetFiles(TextBox1.Text,
FileIO.SearchOption.SearchAllSubDirectories, "*.mp4", "*.jpg", "*.wav", "*.pf_import")
length += My.Computer.FileSystem.GetFileInfo(f).Length
Next
Then convert from bytes to megabytes:
Dim totalKB As Double = length/1024.0 ' To Kilobytes
Dim totalMB As Double = totalKB/1000 ' To Megabytes

Select files from directory order of there names

I have 'N' number of files in a folder, the file names follows some common procedure(file0....fileN). the file names looks like:
file1.pdf
..
file7.pdf
..
file10.pdf
..
file15.pdf
..
fileN.pdf
Am collecting these files into a list of string using the following code:
Dim Files As String() = Directory.GetFiles(folderBase + "\files", "*.pdf")
here what is the problem am facing is that am getting in the list in the following order:
file1.pdf
file10.pdf
..
file2.pdf
..
file15.pdf
..
fileN.pdf
Getting file10.pdf after file1.pdf. i want to get file names in the sequential order(file1.pdf,file2.pdf...etc)
i have tried this also but it will not solve my problem:
Dim Files As List(Of String) = Directory.GetFiles(folderBase + "\files", "*.pdf").OrderBy(Function(f) New FileInfo(f).Name).ToList()
If you need to use an array then sort function can be used
Dim Files As String() = Directory.GetFiles(folderBase + "\files", "*.pdf")
System.Array.Sort(Of String)(Files)
Here is an approach that uses sorted dictionary. It assumes that the file names are letters followed by number(s). This works by making the file names the same length and using that as the key for the sorted dictionary.
'get the file name only
Dim fnames As IEnumerable(Of String) = From f In Files
Select IO.Path.GetFileNameWithoutExtension(f)
'get the longest file name
Dim max As Integer = fnames.Max(Function(fs) fs.Length)
'a palce for the results
Dim sd As New SortedDictionary(Of String, String)
Dim nums() As Char = "0123456789".ToCharArray
'create dictionary entries.
For ix As Integer = 0 To fnames.Count - 1
Dim fn As String = fnames(ix)
Dim idx As Integer = fn.IndexOfAny(nums)
If idx >= 0 Then fn = fn.Insert(idx, New String(" "c, max - fn.Length))
sd.Add(fn, Files(ix))
Next
Dim l As List(Of String) = sd.Values.Select(Function(f) IO.Path.GetFileName(f)).ToList
When working with paths use the methods in IO.Path, e.g.
Dim Files As String() = IO.Directory.GetFiles(IO.Path.Combine(folderBase, "files"), "*.pdf")
One other thing, use & for concatenation of strings not +.

How to avoid "Out Of Memory" exception when reading large files using File.ReadAllText(x)

This is my code to search for a string for all files and folders in the drive "G:\" that contains the string "hello":
Dim path = "g:\"
Dim fileList As New List(Of String)
GetAllAccessibleFiles(path, fileList)
'Convert List<T> to string array if you want
Dim files As String() = fileList.ToArray
For Each s As String In fileList
Dim text As String = File.ReadAllText(s)
Dim index As Integer = text.IndexOf("hello")
If index >= 0 Then
MsgBox("FOUND!")
' String is in file, starting at character "index"
End If
Next
This code will also results in memory leak/out of memory exception (as I read file as big as 5GB!). Perhaps it will bring the whole file to the RAM, then went for the string check.
Dim text As String = File.ReadAllText("C:\Users\Farizluqman\mybigmovie.mp4")
' this file sized as big as 5GB!
Dim index As Integer = text.IndexOf("hello")
If index >= 0 Then
MsgBox("FOUND!")
' String is in file, starting at character "index"
End If
But, the problem is: This code is really DANGEROUS, that may lead to memory leak or using 100% of the RAM. The question is, is there any way or workaround for the code above? Maybe chunking or reading part of the file and then dispose to avoid memory leak/out of memory? Or is there any way to minimize the memory usage when using the code? As I felt responsible for other's computer stability. Please Help :)
You should use System.IO.StreamReader, which reads line by line instead all the lines at the same time (here you have a similar post in C#); I personally never use ReadAll*** unless under very specific conditions. Sample adaptation of your code:
Dim index As Integer = -1
Dim lineCount As Integer = -1
Using reader As System.IO.StreamReader = New System.IO.StreamReader("C:\Users\Farizluqman\mybigmovie.mp4")
Dim line As String
line = reader.ReadLine
If (line IsNot Nothing AndAlso line.Contains("hello")) Then
index = line.IndexOf("hello")
Else
If (line IsNot Nothing) Then lineCount = line.Length
Do While (Not line Is Nothing)
line = reader.ReadLine
If (line IsNot Nothing) Then
lineCount = lineCount + line.Length
If (line.Contains("hello")) Then
index = lineCount - line.Length + line.IndexOf("hello")
Exit Do
End If
End If
Loop
End If
End Using
If index >= 0 Then
MsgBox("FOUND!")
' String is in file, starting at character "index"
End If

Array basics - Populating with loop

I'm looping through a zip file trying to add the file name of each file within.
Is this the correct method?
Dim ZipNameArray(?)
Using zip As ZipFile = ZipFile.Read(ZipToUnpack)
For Each file In zip
ZipNameArray(?) = file .FileName
Next
End Using
I do not know the array size until I start looping through the zip (To work out the number of files within).
How do I increment the Array? file is not a number? (It's a ZipEntry)
I would use an generic List(of ZipFile) for this. They are more fail-safe and easier to read.
Dim zips as new List(of ZipFile)
Using zip As ZipFile = ZipFile.Read(ZipToUnpack)
For Each file In zip
zips.add(file)
Next
End Using
And when you want to iterate through:
For each zip as ZipFile in zips
dim fileName as string=zip.FileName
Next
In 99% you can forget Arrays in .Net and when you need one you get it with List.ToArray
You could use an ArrayList object, add the items to it, then call .ToArray() at the end to get an array of ZipEntry objects.
Since you don't know the array size there are two options. You could go through the Zip file twice. The first time just count the number of files, then create your array and then go through a second time to add the name of each file.
If your zip file is too large you could always initialize your array to some constant number (say 10) and when you reach the eleventh filename you grow your array by "redim"ing it
For example:
Dim Names(10) as String
Dim counter as Integer
counter = 0
Go through zip {
counter += 1
if counter = size of Names then
ReDim Preserve Names(size of Names + 10)
add fileName
}
More information about arrays (including redim) is here.
Dim zipNameArray As String()
Using zip As ZipFile = ZipFile.Read(ZipToUnpack)
zipNameArray = zip.Select(Function(file) file.FileName).ToArray()
End Using