Issue using elements in a list in FOR EACH loop - vb.net

I am new to VB.net and want to write an application to read a text file with a list of paths, count the number of files in all the paths, copy the everything in the path and show the progress via a progress bar with an eta of completion.
So far I have only the text file being read and the counter working correctly, but cannot work out how to use the paths already stored in pathlist list to be the sources in the copy. Here is what I have;
Public Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If System.IO.File.Exists(Application.StartupPath + "\CONFIG.txt") = True Then
Dim pathlist As New List(Of String)
' Open config.txt with the Using statement.
Using r As StreamReader = New StreamReader(Application.StartupPath + "\CONFIG.txt")
' Store contents in this String.
Dim line As String
' Read first line.
line = r.ReadLine
' Loop over each line in file, While list is Not Nothing.
Do While (Not line Is Nothing)
' Add this line to list.
pathlist.Add(line)
'count the files in the directories as we go through the loop
counter = System.IO.Directory.GetFiles(line, "*.*", SearchOption.AllDirectories).Count()
'add # of files to overall count
filecount += counter
' Read the next line.
line = r.ReadLine
Loop
End Using
Else
MessageBox.Show("Config.txt does not exist")
End If
'Label Showing total files
Label1.Text = filecount
End Sub
How would I use the line strings in pathlist to do the following:
Copy the folder with all subfile and directories to the destination folder
Update a counter so I can use a progress bar
Do an time remaining counter, how can this be estimated? Should I be calculating the size in MB's of all the data? Or something similar?
If anyone can assist or link me an example I could use, that would be great!

Related

Iterate through a directory to get subfolders and certain files

I am working on a program that will move files to a database, text files to be exact. The user will have a starting directory and inside will multiple sub folders and files and so on. I want to go through each Folder and sub folder looking for the text files and add them accordingly to the database so it resembles a directory structure in a way. In the program the files are organized such as the folders are "Categories" that are displayed into a tree view.I am only adding the folder names(as Categories) that do contain text files and their subs and so forth. As well I need to figure out where to plug in the adding of the "Category". As of right now I am using a couple of listboxes for my output until I can get it all figured out.
lstfiles.Items.Add(Dir)
For Each file In System.IO.Directory.GetFiles(Dir)
Dim fi As System.IO.FileInfo = New IO.FileInfo(file)
If fi.Extension = ".txt" Then
If lstRootFolderFiles.Items.Contains(file) = False Then
lstfiles.Items.Add(file)
AddFile(file, Gennumber(9999))
End If
End If
Next
For Each folder In System.IO.Directory.GetDirectories(Dir)
lstfiles.Items.Add(folder)
For Each file In System.IO.Directory.GetFiles(folder)
Dim fi As System.IO.FileInfo = New IO.FileInfo(file)
If fi.Extension = ".txt" Then
If lstRootFolderFiles.Items.Contains(file) = False Then
lstfiles.Items.Add(file)
End If
End If
Next
Next
I have gotten so far as to iterate through the directory and get files but it returns folders that are empty. And I need to figure out where I need to put in my addcategory function. And also remember the last one that was added so they can be added as a subcategory.
I think I am making a big mess of it all, or over thinking the whole thing.
Any assistance or guidance would be appreciated.Thank you
The end result that I came up with was much different from my original posting, as it was my way of thinking of how it was going to work. I split up the two main functions. Retrieving the Folders and retrieving the files.
DirEx is the Import Directory, CatID is the Tag of the selected Treenode where the folders are going to added in.
Private Sub DirImport_GetSubDirectories(ByVal DirEx As String, ByVal CatID As Integer)
Try
Dim ClsData As New clsNoteData
'Set the DatabaseFile Property of the class
ClsData.Database = LoadedLibraryDatabase
' Get all subdirectories
Dim subdirectoryEntries() As String = Directory.GetDirectories(DirEx)
' Loop through them to see if they have any other subdirectories
Dim subdirectory As String
For Each subdirectory In subdirectoryEntries
'If the Directory is not Empty
If Not Directory.GetFileSystemEntries(subdirectory).Length = 0 Then
Dim di As DirectoryInfo = New DirectoryInfo(subdirectory)
'Creating Random Number
Dim NewCatID As Integer = GenNumber(9999)
'Call for a new Sub Category
ClsData.NewSubCategoryNode(LoadedLibraryDatabase, NewCatID, CatID, di.Name, -1)
'Get files in the current Directory
DirImport_GetFiles(subdirectory, NewCatID)
'Get the next set of Subfolders
DirImport_GetSubDirectories(subdirectory, NewCatID)
End If
Next
Catch ex As Exception
End Try
End Sub
Private Sub DirImport_GetFiles(ByVal DirEx As String, ByVal CatID As Integer)
Dim Files() As String = Directory.GetFiles(DirEx, "*.txt")
Dim file As String
For Each file In Files
Dim clsNoteData As New clsNoteData
Dim fi As FileInfo = New FileInfo(file)
clsNoteData.Database = LoadedLibraryDatabase
clsNoteData.NewNote_ID = GenNumber(99999)
clsNoteData.NewNote_CatID = CatID
clsNoteData.NewNote_Title = Path.GetFileNameWithoutExtension(file)
clsNoteData.NewNote(False, file)
Next
End sub
So here it is for anyone who may want to do something similar.

Copying a list of modified files from multiple source directories to equivalent destination directory

I am learning VB.NET and writing a utility to copy only the modified files from a preset selection of folders to their equivalent in a backup directory.
For example: D:\Profiles\Mail to E:\Backup\Profiles\Mail
I can already do the copy simply with the following:
For Each item In MAILp
My.Computer.FileSystem.CopyDirectory(MAILp, MAILd, True)
Next
But the idea is count the amount of modified files to be copied, and display this all through a progress bar and the background worker (eventually)
At the moment i am working with this;
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'Contants for whole activity
Dim lstFiles As New List(Of FileInfo)
Dim fsInfo As FileSystemInfo
'Constants for dirInfo's
Dim dirInfoMAILp As New DirectoryInfo(MAILp)
Dim dirInfoDESKTOPp As New DirectoryInfo(DESKTOPp)
'Loop for Mail
For Each fsInfo In dirInfoMAILp.GetFileSystemInfos
Dim strDestFileName As String = Path.Combine(MAILd, fsInfo.Name)
Dim destFileInfo As New FileInfo(strDestFileName)
If fsInfo.LastWriteTime > destFileInfo.LastWriteTime Then
lstFiles.Add(fsInfo)
End If
Next
'Loop for Desktop
For Each fsInfo In dirInfoDESKTOPp.GetFileSystemInfos
Dim strDestFileName As String = Path.Combine(DESKTOPd, fsInfo.Name)
Dim destFileInfo As New FileInfo(strDestFileName)
If fsInfo.LastWriteTime > destFileInfo.LastWriteTime Then
lstFiles.Add(fsInfo)
End If
Next
'Number of files to copy
Label1.Text = lstFiles.Count
For Each file As FileInfo In lstFiles
System.IO.File.Copy(file.FullName, DESTINATIONMAIN + file.Name, True)
Next
End Sub
My problem is in three parts:
1. If the files do not already exist in the destination, it will throw and exception. This is not good if the utility is being used for the first time. How can I use an ELSE in the loop to copy the file if it doesn't exist in the destination?
2. The copy does not copy folders, only files, can I expand it to include folders? Ideally the differential check loop targets the Top folder then goes through every sub folder and file, adding it to the list.
3. When copied to the destination folder, the files are copied to the destination top folder "E:\Backup\Profiles", rather than in the sub-folders they were copied from.
Can anyone point me in the right direction?

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.

Loop to print text files is skipping some files(randomly, it seems)

I have a VB.NET program which lists some text files in a directory and loops through them. For each file, the program calls notepad.exe with the /p parameter and the filename to print the file, then copies the file to a history directory, sleeps for 5 seconds(to allow notepad to open and print), and finally deletes the original file.
What's happening is, instead of printing every single text file, it is only printing "random" files from the directory. Every single text file gets copied to the history directory and deleted from the original however, so I know that it is definitely listing all of the files and attempting to process each one. I've tried adding a call to Thread.Sleep for 5000 milliseconds, then changed it to 10000 milliseconds to be sure that the original file wasn't getting deleted before notepad grabbed it to print.
I'm more curious about what is actually happening than anything (a fix would be nice too!). I manually moved some of the files that did not print to the original directory, removing them from the history directory, and reran the program, where they DID print as they should, so I know it shouldn't be the files themselves, but something to do with the code.
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim f() As String = ListFiles("l:\", "997")
Dim i As Integer
Try
For i = 0 To f.Length - 1
If Not f(i) = "" Then
System.Diagnostics.Process.Start("Notepad.exe", " /p l:\" & f(i))
My.Computer.FileSystem.CopyFile("l:\" & f(i), "k:\" & f(i))
'Thread.Sleep(5000)
Thread.Sleep(10000)
My.Computer.FileSystem.DeleteFile("l:\" & f(i))
End If
Next
'Thread.Sleep(5000)
Thread.Sleep(10000)
Catch ex As Exception
End Try
End Sub
Public Function ListFiles(ByVal strFilePath As String, ByVal strFileFilter As String) As String()
'finds all files in the strFilePath variable and matches them to the strFileFilter variable
'adds to string array strFiles if filename matches filter
Dim i As Integer = 0
Dim strFileName As String
Dim strFiles(0) As String
Dim strExclude As String = ""
Dim pos As Integer = 0
Dim posinc As Integer = 0
strFileName = Dir(strFilePath)
Do While Len(strFileName) > 0
'check to see if filename matches filter
If InStr(strFileName, strFileFilter) Then
If InStr(strFileName, "997") Then
FileOpen(1, strFilePath & strFileName, OpenMode.Input)
Do Until EOF(1)
strExclude = InputString(1, LOF(1))
Loop
pos = InStr(UCase(strExclude), "MANIFEST")
posinc = posinc + pos
pos = InStr(UCase(strExclude), "INVOICE")
posinc = posinc + pos
FileClose(1)
Else : posinc = 1
End If
If posinc > 0 Then
'add file to array
ReDim Preserve strFiles(i)
strFiles(i) = strFileName
i += 1
Else
My.Computer.FileSystem.MoveFile("l:\" & strFileName, "k:\" & strFileName)
End If
'MsgBox(strFileName & " " & IO.File.GetLastWriteTime(strFileName).ToString)
pos = 0
posinc = 0
End If
'get the next file
strFileName = Dir()
Loop
Return strFiles
End Function
Brief overview of the code above. An automated program fills the "L:\" directory with text files, and this program needs to print out certain files with "997" in the filename (namely files with "997" in the filename and containing the text "INVOICE" or "MANIFEST"). The ListFiles function does exactly this, then back in the Form1_Load() sub it is supposed to print each file, copy it, and delete the original.
Something to note, this code is developed in Visual Studio 2013 on Windows 7. The machine that actually runs this program is still on Windows XP.
I can see a few issues. the first and most obvious is the error handling:
You have a Try.. Catch with no error handling. You may be running in to an error without knowing it!! Add some output here, so you know if that is the case.
The second issue is to do with the way you are handling Process classes.
Instead of just calling System.Diagnostics.Process.Start in a loop and sleeping you should use the inbuilt method of handling execution. You are also not disposing of anything, which makes me die a little inside.
Try something like
Using p As New System.Diagnostics.Process
p.Start("Notepad.exe", " /p l:\" & f(i))
p.WaitForExit()
End Using
With both of these changes in place you should not have any issues. If you do there should at least be errors for you to look at and provide here, if necessary.

Writing to a text file in Visual Basic stops at 3074 bytes. Any idea why?

I have developed a small program using Visual Basic Express 2010 that reads a file, scans it line by line, when the line contains some specific text, it manipulates the text and writes that manipulated text to a new file, if that condition is not met, it writes the original line.
It is working ok, gives no errors and completes the run. However, it stops writing to the file at some point. I have checked the files and the only common thing I find between the several tests is that the new files all have 3074 bytes as size. Is this a limitation of VB Express? Am I using the wrong way of writing to the file?
Here a reduced version of the code:
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim Linha As String
Dim datapag As String
'Open File
If OpenFileDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then
Dim novoficheiro As New System.IO.StreamWriter(OpenFileDialog1.FileName + "2.xml")
Dim Ficheiro As New System.IO.StreamReader(OpenFileDialog1.FileName)
'Scan lines one at a time
Do While Ficheiro.Peek <> -1
Linha = Ficheiro.ReadLine
Dim tratada As Boolean
tratada = False
'Make some changes in specific conditions
If Linha.Contains("<PaymentDueDate>") Then
datapag = Mid(Linha, 17, 8)
Dim composta, Novalinha3 As String
composta = Mid(datapag, 1, 4) + "-"
composta = composta + Mid(datapag, 5, 2) + "-"
composta = composta + Mid(datapag, 7, 2)
Novalinha3 = Replace(Linha, datapag, composta)
novoficheiro.WriteLine(Novalinha3)
tratada = True
End If
'If no changes were made write the original line
If tratada = False Then
novoficheiro.WriteLine(Linha)
End If
Loop
End If
End Sub
End Class
So, the idea is that I have a new version of the file with just some lines changed.
I have added messages throughout the code to show me the contents of the lines sent to the new file and they are all parsed ok, corrected correctly when needed and unchanged when no correction is necessary.
The file just gets truncated at some point, depending on how many different conditions I handle but always resulting in a file with 3074 byte size (the original file is 2787 bytes long, BTW).
Any help?
Thanks in advance!
I believe that you need to flush and close the StreamWriter after your done writing the file and before you exit the function. After the Loop and before the End If, add the line:
novoficheiro.Close()
This should fix the issue.