VB.NET iterating through files and directories - vb.net

I'm working on a VB.NET program that will automatically backup my work to my FTP server. So far I am able to upload a single file, by specifying a file name using this:
'relevant part - above is where FTP object is instantiated
Dim _FileStream As System.IO.FileStream = _FileInfo.OpenRead()
Try
'Stream to which the file to be upload is written
Dim _Stream As System.IO.Stream = _FtpWebRequest.GetRequestStream()
'Read from the file stream 2kb at a time
Dim contentLen As Integer = _FileStream.Read(buff, 0, buffLength)
'Till Stream content ends
Do While contentLen <> 0
' Write Content from the file stream to the FTP Upload Stream
_Stream.Write(buff, 0, contentLen)
contentLen = _FileStream.Read(buff, 0, buffLength)
Loop
_Stream.Close()
_Stream.Dispose()
_FileStream.Close()
_FileStream.Dispose()
' Close the file stream and the Request Stream
Catch ex As Exception
MessageBox.Show(ex.Message, "Upload Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
Now I want to be able to iterate through a directory (Which contains subdirectories) and recursively call the function above. I'm having a problem getting a hold of the files in the directory.
My Question is, How can I loop through and send each file to the upload function above? Can I just send the filename to an array, or is there some sort of system object to handle this (e.g. System.IO.Directory)
Pseudocode for what I'm trying to do
For Each Sub_directory In Source_directory
For Each File in Directory
'call the above code to transfer the file
Next
'start next subdirectory
Next
I'm trying to replicate the entire directory structure with sub directories intact. My first attempt dumped ALL files into one directory.

You could go through each directory and file using recursion like this:
Public Shared Sub ForEachFileAndFolder(ByVal sourceFolder As String, _
ByVal directoryCallBack As Action(Of DirectoryInfo), _
ByVal fileCallBack As Action(Of FileInfo))
If Directory.Exists(sourceFolder) Then
Try
For Each foldername As String In Directory.GetDirectories(sourceFolder)
If directoryCallBack IsNot Nothing Then
directoryCallBack.Invoke(New DirectoryInfo(foldername))
End If
ForEachFileAndFolder(foldername, directoryCallBack, fileCallBack)
Next
Catch ex As UnauthorizedAccessException
Trace.TraceWarning(ex.Message)
End Try
If fileCallBack IsNot Nothing
For Each filename As String In Directory.GetFiles(sourceFolder)
fileCallBack.Invoke(New FileInfo(filename))
Next
End If
End If
End Sub
Edit: Usage of the Delegates:
ForEachFileAndFolder("yourPath", AddressOf dirAction, Addressof fileAction)
Public Sub dirAction(Byval dirInfo As DirectoryInfo)
' do something here '
End Sub
Same for the FileAction.

You'll have to handle directories and files separatly, but it's still pretty simple.
System.IO.DirectoryInfo constains the list files and sub-directories within a specified directory. Look for the property directories and files.
What you will want to do is specify a function that will read through all files first and then directories within the DirectoryInfo. For the files, you do what you want to do with it (Upload I think), and once you hit the Directories, call your function recursivly using the sub directory as the argument. This will go thourh all sub-directories and file.
Pseudo-Code (I call it pseudo-code cos' I don't know the exact syntax)
Sub UploadDirectory(oDirInfo as DirectoryInfo)
For eaco oFile as FileInfo in oDirINfo.Files
'Do your thing
Next
For each oDir as DirectoryInfo as oDirInfo.Directories
' Do some stuff if you need to separate directories
UploadDirectory(odir)
End sub
Hope that helps.

Have a look at the DirectoryInfo class.

Related

vb.net search directory for files containing *.G(num) but NOT *.GP(num)

I'm fairly familiar with bash, but I'm very, ***very**** new to vb.net. I'm searching for an easy way to find files in a folder that end with .G1, .G2, .G3, etc. but NOT .GP1, .GP2, .GP3, etc. Then for each file I need to copy it to another folder using a different file name but the same extension. I've managed to figure this out for the unique files, but there will be an undefined number of these depending on the project and I need to make sure that I get them all. Hard coding is possible, but very, very ugly. Any suggestions?
Here's the remnants of a failed attempt:
Public Sub FindGFiles()
FileList = IO.Directory.GetFiles(searchDir, ".G[1-99]" + , IO.SearchOption.AllDirectories)
For Each foundfile As String In FileList
If foundfile.Contains(".G#") Then
'copy file somehow and retain file extension
Else
MsgBox("No match")
End If
Next
End Sub
The GetFiles-method does only support * and ? wildcard characters.
So you have to get all files with a *.G*-extension first.
In the For Each-loop one can then use the Like-operator to check the desired pattern:
Public Sub CopyGFiles(searchDir As String, destDir As String)
Dim fileList As String() = IO.Directory.GetFiles(searchDir, "*.G*", IO.SearchOption.AllDirectories)
Dim fileName As String
Dim extension As String
For Each foundfile As String In fileList
fileName = IO.Path.GetFileNameWithoutExtension(foundfile)
extension = IO.Path.GetExtension(foundfile)
If extension Like ".G#" OrElse
extension Like ".G##" Then
'copy file to destination, append "_new" to the filename and retain file extension
IO.File.Copy(foundfile, IO.Path.Combine(destDir, fileName & "_new" & extension))
Else
'pattern not matched
End If
Next
End Sub
The method-call would then be as follows:
CopyGFiles("C:\Temp", "C:\Temp\Dest")
This should be done inside a Try/Catch as different exceptions can occur when working with files.
Try
CopyGFiles("C:\Temp", "C:\Temp\Dest")
Catch ex As Exception
MessageBox.Show("An error occured" + vbCrLf + ex.Message)
End Try

How to check if a file/folder exists in the C drive VB.NET

i'm trying to create a simple anti-cheat which detects external cheats in all the C drive, but i don't know how to check if a determinate file exists in all the C drive, any help?
Here is code that I adapted from How to: Iterate Through a Directory Tree. In the example, the FileExists() function returns True if the file bit32.txt is found anywhere on the C drive. Not all files and directories may be accessible. In that case, the function display the paths of these files and directories. You may want to adapt the code to do whatever you want in these cases.
Imports System.IO
Module Module1
Private Sub Main(ByVal args() As String)
Dim exists As Boolean = FileExists(New DriveInfo("C").RootDirectory, "bit32.txt")
End Sub
Private Function FileExists(ByVal root As DirectoryInfo, ByVal filename As String) As Boolean
Dim files() As FileInfo = Nothing
Dim subDirs() As DirectoryInfo = Nothing
' First, process all the files directly under this folder
Try
files = root.GetFiles("*.*")
Catch e As Exception
' This code just writes out the message and continues to recurse.
' You may decide to do something different here. For example, you
' can try to elevate your privileges and access the file again.
Console.WriteLine(e.Message)
End Try
If (Not (files) Is Nothing) Then
For Each fi As FileInfo In files
' In this example, we only access the existing FileInfo object. If we
' want to open, delete or modify the file, then
' a try-catch block is required here to handle the case
' where the file has been deleted since the call to TraverseTree().
'Console.WriteLine(fi.FullName);
If (fi.Name = filename) Then
Return True
End If
Next
End If
Try
' Now find all the subdirectories under this directory.
subDirs = root.GetDirectories
For Each dirInfo As DirectoryInfo In subDirs
' Resursive call for each subdirectory.
If FileExists(dirInfo, filename) Then
Return True
End If
Next
Catch e As Exception
' This code just writes out the message and continues to recurse.
' You may decide to do something different here. For example, you
' can try to elevate your privileges and access the file again.
Console.WriteLine(e.Message)
End Try
Return False
End Function
End Module
You can have an extension on DirectoryInfo that non-recursively iterates through the root directory looking for files.
<Extension()>
Public Iterator Function GetFilesDepthFirst(ByVal root As DirectoryInfo, ByVal Optional dirPattern As String = "*", ByVal Optional filePattern As String = "*.*") As IEnumerable(Of FileInfo)
Dim stack = New Stack(Of DirectoryInfo)()
stack.Push(root)
While stack.Count > 0
Dim current = stack.Pop()
Dim files = Enumerable.Empty(Of FileInfo)()
Dim dirs = Enumerable.Empty(Of DirectoryInfo)()
Try
dirs = current.EnumerateDirectories(searchPattern:=dirPattern)
files = current.EnumerateFiles(searchPattern:=filePattern)
Catch ex1 As UnauthorizedAccessException
Catch ex2 As PathTooLongException
End Try
For Each file As FileInfo In files
Yield file
Next
For Each dir As DirectoryInfo In dirs
stack.Push(dir)
Next
End While
End Function
You could then call it fairly easily like this:
Dim dInfo = New DirectoryInfo("C:\")
Dim matches = dInfo.GetFilesDepthFirst(filePattern:="somefile.dll")
Dim exists = matches.Any()
Also, the more specific you are at the starting directory, the quicker it will run. Usually searching from the root of C:\ is a very slow and bad idea.

ftp download stopping before end of list

I'm using the following code to download files from an FTP server. Before entering this code, I have created a list of filenames from files that are in the directory on the FTP server. There are over 2000 files in the list.
As I iterate through the list, the files download properly until I reach exactly 121 files downloaded. Then it starts giving me an error of "file not found, access denied." for every file after that. However the files are there. If I start the process over again it will pick up from where it left off and download another 121 files and continue until it errors again after the next 121 files.
Here is the code:
For Each file As String In dirlist
DownloadFile(local_path + "\" + filename, new_path + "/" + Trim(filename), client)
Next
Private Sub DownloadFile(ByVal localpath As String, ByVal ftpuri As String, client As String)
Dim request As New WebClient()
request.Credentials = New NetworkCredential(user_name, password)
Dim bytes() As Byte = request.DownloadData(ftpuri)
Try
Dim DownloadStream As FileStream = IO.File.Create(localpath)
DownloadStream.Write(bytes, 0, bytes.Length)
DownloadStream.Close()
Catch ex As Exception
add_to_log(log_window, ex.Message)
End Try
End Sub
I do not understand why it is stopping before completing the list.

How to Access a txt file in a Folder created inside a VB project

I'm creating a VB project for Quiz App (in VS 2013). So I have some preset questions which are inside the project (I have created a folder inside my project and added a text file).
My question is how can I read and write contents to that file? Or if not is there any way to copy that txt file to Documents/MyAppname when installing the app so that I can edit it from that location?
In the example below I am focusing on accessing files one folder under the executable folder, not in another folder else wheres. Files are read if they exists and then depending on the first character on each line upper or lower case the line then save data back to the same file. Of course there are many ways to work with files, this is but one.
The following, created in the project folder in Solution Explorer a folder named Files, add to text files, textfile1.txt and textfile2.txt. Place several non empty lines in each with each line starting with a character. Each textfile, set in properties under solution explorer Copy to Output Directory to "Copy if newer".
Hopefully this is in tune with what you want. It may or may not work as expected via ClickOnce as I don't use ClickOnce to validate this.
In a form, one button with the following code.
Public Class Form1
Private TextFilePath As String =
IO.Path.Combine(
AppDomain.CurrentDomain.BaseDirectory, "Files")
Private TextFiles As New List(Of String) From
{
"TextFile1.txt",
"TextFile2.txt",
"TextFile3.txt"
}
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim FileName As String = ""
' loop thru each file
For Each fileBaseName As String In TextFiles
FileName = IO.Path.Combine(TextFilePath, fileBaseName)
' only access file if it exist currently
If IO.File.Exists(FileName) Then
' read file into string array
Dim contents As String() = IO.File.ReadAllLines(FileName)
' upper or lower case line based on first char.
' this means you can flip flop on each click on the button
For x As Integer = 0 To contents.Count - 1
If Char.IsUpper(CChar(contents(x))) Then
contents(x) = contents(x).ToLower
Else
contents(x) = contents(x).ToUpper
End If
Next
' save changes, being pesstimistic so we use a try-catch
Try
IO.File.WriteAllLines(FileName, contents)
Catch ex As Exception
Console.WriteLine("Attempted to save {0} failed. Error: {1}",
FileName,
ex.Message)
End Try
Else
Console.WriteLine("Does not exists {0}", FileName)
End If
Next
End Sub
End Class
This may help you
Dim objStreamReader As StreamReader
Dim strLine As String
'Pass the file path and the file name to the StreamReader constructor.
objStreamReader = New StreamReader("C:\Boot.ini")
'Read the first line of text.
strLine = objStreamReader.ReadLine
'Continue to read until you reach the end of the file.
Do While Not strLine Is Nothing
'Write the line to the Console window.
Console.WriteLine(strLine)
'Read the next line.
strLine = objStreamReader.ReadLine
Loop
'Close the file.
objStreamReader.Close()
Console.ReadLine()
You can also check this link.

Ignore errors when scanning for files in C:

I am trying to search the C:\ drive for all files with a certain extension. I am using the following code which is working fine, however when it encounters an error the whole process stops rather than continuing with the scan. (running in backgroundworker, hence the invoke)
Private Sub ScanFiles(ByVal rootFolder As String, ByVal fileExtension As String)
'Determine if the current folder contains any sub folders
Dim subFolders() As String = System.IO.Directory.GetDirectories(rootFolder)
For Each subFolder As String In subFolders
ScanFiles(subFolder, fileExtension)
Next
For Each file As String In System.IO.Directory.GetFiles(rootFolder, fileExtension)
lb.BeginInvoke(New AddValue(AddressOf AddItems), file)
Next
End Sub
How can I make this code continue once an error is encountered?
If you don't have access to explore C drive itself then you are out of luck. but if you are getting an exception because you don't have access to some child folder in the tree, you can avoid it by putting your code in an try-catch block.
Private Sub ScanFiles(ByVal rootFolder As String, ByVal fileExtension As String)
'Determine if the current folder contains any sub folders '
try
Dim subFolders() As String = System.IO.Directory.GetDirectories(rootFolder)
For Each subFolder As String In subFolders
ScanFiles(subFolder, fileExtension)
Next
For Each file As String In System.IO.Directory.GetFiles(rootFolder, fileExtension)
lb.BeginInvoke(New AddValue(AddressOf AddItems), file)
Next
catch (Ex As UnauthorizedAccessException)
'Ignore Access Errors '
end try
End Sub