Iterating through a list of folders

Hello all,

SUper Noob here. I have a very basic question regarding iteration through a list of folders that I need to search. The object of this program is to look for files older then 10 days old in a given set of folders. As much as I dont mind doing if statements for each folder object I specified, I would like to be able to grow the list and not have excessive code. Anyway, any and all suggestions would be greatly appcriciated. Thank you and take care.

This is what I have now:

Sub Main()

Dim fso, Efile, EFolder1, Efolder2

fso = CreateObject("Scripting.FileSystemObject")

EFolder1 = fso.getfolder("C:\temp2")

Efolder2 = fso.getfolder("C:\temp3")

ForEach EfileIn Efolder2

If DateDiff("d", Efile.datelastmodified, Now) > 10Then

Efile.delete()

EndIf

Next

Efile =Nothing

ForEach EfileIn EFolder1

If DateDiff("d", Efile.datelastmodified, Now) > 10Then

Efile.delete()

EndIf

Nex

EndSub

NOTE : I tried using the "collection class" to store the efolder objects, however was not able to loop through the collection.

[2533 byte] By [Nub1] at [2007-12-25]
# 1

ok lets see - we need to clean up your code!

Why are you creating an fso? Why dont you use the System.IO.Directory.GetDirectories() or GetFiles() class?

Dim theFolders() as String = System.IO.Directories.GetDirectories("Path")

Dim theFilesToDelete as new ArrayList()

for each currentFolder as String in theFolders

Dim theFilesInCurrentFolder() as String = System.IO.Directories.GetFiles(currentFolder)

for each currentFile as String in theFilesInCurrentFolder

'get the LastAccessTime of the file

Dim theFileInfo as new FileInfo(currentFile)

'If statement goes here to check the LastAccessTime of the File and see if its 10 days or more from today's date

theFilesToDelete.Add(currentFile)

end if

next

next

for each currentFile as String in theFilesToDelete

System.IO.File.Delete(currentFile)

next

does this help/make you understand better?

ahmedilyas at 2007-8-31 > top of Msdn Tech,Visual Basic,Visual Basic Language...
# 2
Thank you for your reply. I understand the array portion, and the

general use of the system.IO, and I even understand how you are

traversing each directory with the "for each currentfolder"

statement, but I am a little confused with :

Dim theFolders() as new String = System.IO.Directories.GetDirectories("Path")

can path = more than one directory.... e.g.

Dim theFolders() as new String = System.IO.Directories.GetDirectories("C:\temp2, C:\temp3")

?

Thanks again for your help!

-A noob

Nub1 at 2007-8-31 > top of Msdn Tech,Visual Basic,Visual Basic Language...
# 3

The path cannot be more than 1 directory unfortunately I believe. if you specify "C:\" it will get a list of folders in C:\ (the root directory of your harddrive).

You can however specify a search pattern? The search pattern will give you back the folders which contain the specified search "expression"

so logically/in theory if you did this:

Dim theFolders() as String = System.IO.Directories.GetDirectories("C:\", "temp*")

it should return you back all folders which start with "temp", since we specified "temp" and an astrix to indicate that the folders must start with temp and have anything else after it

Also note, it should be "as String" and not "as new String" - which I will correct in my original reply :-)

ahmedilyas at 2007-8-31 > top of Msdn Tech,Visual Basic,Visual Basic Language...
# 4

Here's some example code. You create a subroutine that does the actual deletion and call that sub for each folder that you want to check. This way the code does not change no matter how many folders need to be checked. You just keep calling the same routine and passing in the folder path. This example also takes parameters for the type of files to check based on name and/or extension (e.g. *.* for all files) and it takes a True/False that specifies whether to search each sub directory in the given path.

Here's the example:

'Create a sub to delete the old files

'Tell the routine the path to delete from, whether to check sub directories, and what file names and/or types to delete

Private Sub DeleteOldFiles(ByVal path As String, ByVal includeSubDir As Boolean, Optional ByVal fileFilter As String = "*.*")

'Check if the path supplied exists

If System.IO.Directory.Exists(path) Then

'Get the search option based on the parameter

Dim opt As System.IO.SearchOption

If includeSubDir Then

opt = IO.SearchOption.AllDirectories

Else

opt = IO.SearchOption.TopDirectoryOnly

End If

'Get the list of files

Dim files() As String = System.IO.Directory.GetFiles(path, fileFilter, opt)

'Loop through each file name in the list

For Each f As String In files

'Get the creation time of the file

Dim created As Date = System.IO.File.GetCreationTime(f)

'If it was created more than 10 days ago...

If Now.Subtract(created).TotalDays > 10 Then

'Delete the file

System.IO.File.Delete(f)

End If

Next

Else

'If the path was invalid throw an exception that says so

Throw New ArgumentException("The path specified does not exist.")

End If

End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

'Delete all old files in C:\temp1 and in all sub directories in C:\temp1

Me.DeleteOldFiles("c:\temp1", True)

'Delete all old files in C:\temp2 but not in any sub directories in C:\temp2

Me.DeleteOldFiles("c:\temp2", False)

'Delete only old text files in C:\temp3 and in all sub directories

Me.DeleteOldFiles("c:\temp3", True, "*.txt")

End Sub

The example code for Button1 just shows three calls to the DeleteOldFiles() method using various parameter options.

Now, if you wanted to, you could create a list of folder paths and loop through the list calling the DeleteOldFiles() method for each entry. In this way the user could specify which folders to check.

HTH!

rkimble at 2007-8-31 > top of Msdn Tech,Visual Basic,Visual Basic Language...
# 5
This is awesome. Thank you soooooooo much for your help. Just wondering what you thought was the best way to pass the diferent folder names to the DeleteOldFiles() func? I was thinking about making an array, and putting the different folders in hte array, and calling it that way. Seems a little complicated(my way that is :) ), anyway, thank you for your example!!! You the man.
Nub1 at 2007-8-31 > top of Msdn Tech,Visual Basic,Visual Basic Language...
# 6

I think that your proposed method of passing the folder names is on target. I would extend it just a tad though... I would create a class to represent each folder (folder path, sub directories option, search pattern option). I would make that class serializable so that the list of folders can be easily saved to/read from disk. Then I would create a List(of T) collection to hold each folder item class object. This list can the be bound to by controls in the UI.

Following is a simple little example application. To try it, start a new Windows Application project. In the Solution Explorer, click the Show All Files button, expand Form1, and open the Form1.Designer.vb code file. You can then paste the section of code below marked Form1.Designer.vb over what is already there. This will layout the form for you. Don't worry about this code too much as it is just what the designer generates as you drag controls onto a form and set their properties.

After you've got the form layout, paste the rest of the code into the Form1.vb code file. This example will demonstrate some simple yet very useful concepts such as object databinding and serialization.

Form1.Designer.vb – This code just sets up the form

<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _

Partial Class Form1

Inherits System.Windows.Forms.Form

'Form overrides dispose to clean up the component list.

<System.Diagnostics.DebuggerNonUserCode()> _

Protected Overrides Sub Dispose(ByVal disposing As Boolean)

If disposing AndAlso components IsNot Nothing Then

components.Dispose()

End If

MyBase.Dispose(disposing)

End Sub

'Required by the Windows Form Designer

Private components As System.ComponentModel.IContainer

'NOTE: The following procedure is required by the Windows Form Designer

'It can be modified using the Windows Form Designer.

'Do not modify it using the code editor.

<System.Diagnostics.DebuggerStepThrough()> _

Private Sub InitializeComponent()

Me.components = New System.ComponentModel.Container

Me.FoldersListBox = New System.Windows.Forms.ListBox

Me.NewPathTextBox = New System.Windows.Forms.TextBox

Me.BrowseButton = New System.Windows.Forms.Button

Me.FolderBrowserDialog1 = New System.Windows.Forms.FolderBrowserDialog

Me.AddButton = New System.Windows.Forms.Button

Me.RemoveButton = New System.Windows.Forms.Button

Me.ExecuteButton = New System.Windows.Forms.Button

Me.SubFoldersCheckBox = New System.Windows.Forms.CheckBox

Me.Label1 = New System.Windows.Forms.Label

Me.PatternTextBox = New System.Windows.Forms.TextBox

Me.BindingSource1 = New System.Windows.Forms.BindingSource(Me.components)

CType(Me.BindingSource1, System.ComponentModel.ISupportInitialize).BeginInit()

Me.SuspendLayout()

'

'FoldersListBox

'

Me.FoldersListBox.FormattingEnabled = True

Me.FoldersListBox.Location = New System.Drawing.Point(12, 94)

Me.FoldersListBox.Name = "FoldersListBox"

Me.FoldersListBox.Size = New System.Drawing.Size(368, 173)

Me.FoldersListBox.TabIndex = 0

'

'NewPathTextBox

'

Me.NewPathTextBox.Location = New System.Drawing.Point(13, 16)

Me.NewPathTextBox.Name = "NewPathTextBox"

Me.NewPathTextBox.Size = New System.Drawing.Size(285, 20)

Me.NewPathTextBox.TabIndex = 1

'

'BrowseButton

'

Me.BrowseButton.Location = New System.Drawing.Point(305, 16)

Me.BrowseButton.Name = "BrowseButton"

Me.BrowseButton.Size = New System.Drawing.Size(75, 23)

Me.BrowseButton.TabIndex = 2

Me.BrowseButton.Text = "Browse"

Me.BrowseButton.UseVisualStyleBackColor = True

'

'AddButton

'

Me.AddButton.Location = New System.Drawing.Point(12, 66)

Me.AddButton.Name = "AddButton"

Me.AddButton.Size = New System.Drawing.Size(115, 23)

Me.AddButton.TabIndex = 3

Me.AddButton.Text = "Add Path"

Me.AddButton.UseVisualStyleBackColor = True

'

'RemoveButton

'

Me.RemoveButton.Location = New System.Drawing.Point(133, 66)

Me.RemoveButton.Name = "RemoveButton"

Me.RemoveButton.Size = New System.Drawing.Size(115, 23)

Me.RemoveButton.TabIndex = 4

Me.RemoveButton.Text = "Remove Path"

Me.RemoveButton.UseVisualStyleBackColor = True

'

'ExecuteButton

'

Me.ExecuteButton.Location = New System.Drawing.Point(12, 274)

Me.ExecuteButton.Name = "ExecuteButton"

Me.ExecuteButton.Size = New System.Drawing.Size(75, 23)

Me.ExecuteButton.TabIndex = 5

Me.ExecuteButton.Text = "Execute"

Me.ExecuteButton.UseVisualStyleBackColor = True

'

'SubFoldersCheckBox

'

Me.SubFoldersCheckBox.AutoSize = True

Me.SubFoldersCheckBox.Location = New System.Drawing.Point(13, 43)

Me.SubFoldersCheckBox.Name = "SubFoldersCheckBox"

Me.SubFoldersCheckBox.Size = New System.Drawing.Size(114, 17)

Me.SubFoldersCheckBox.TabIndex = 6

Me.SubFoldersCheckBox.Text = "Include Subfolders"

Me.SubFoldersCheckBox.UseVisualStyleBackColor = True

'

'Label1

'

Me.Label1.AutoSize = True

Me.Label1.Location = New System.Drawing.Point(133, 44)

Me.Label1.Name = "Label1"

Me.Label1.Size = New System.Drawing.Size(78, 13)

Me.Label1.TabIndex = 7

Me.Label1.Text = "Search Pattern"

'

'PatternTextBox

'

Me.PatternTextBox.Location = New System.Drawing.Point(217, 41)

Me.PatternTextBox.Name = "PatternTextBox"

Me.PatternTextBox.Size = New System.Drawing.Size(100, 20)

Me.PatternTextBox.TabIndex = 8

Me.PatternTextBox.Text = "*.*"

Me.PatternTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center

'

'Form1

'

Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)

Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font

Me.ClientSize = New System.Drawing.Size(399, 312)

Me.Controls.Add(Me.PatternTextBox)

Me.Controls.Add(Me.Label1)

Me.Controls.Add(Me.SubFoldersCheckBox)

Me.Controls.Add(Me.ExecuteButton)

Me.Controls.Add(Me.RemoveButton)

Me.Controls.Add(Me.AddButton)

Me.Controls.Add(Me.BrowseButton)

Me.Controls.Add(Me.NewPathTextBox)

Me.Controls.Add(Me.FoldersListBox)

Me.Name = "Form1"

Me.Text = "Form1"

CType(Me.BindingSource1, System.ComponentModel.ISupportInitialize).EndInit()

Me.ResumeLayout(False)

Me.PerformLayout()

End Sub

Friend WithEvents FoldersListBox As System.Windows.Forms.ListBox

Friend WithEvents NewPathTextBox As System.Windows.Forms.TextBox

Friend WithEvents BrowseButton As System.Windows.Forms.Button

Friend WithEvents FolderBrowserDialog1 As System.Windows.Forms.FolderBrowserDialog

Friend WithEvents AddButton As System.Windows.Forms.Button

Friend WithEvents RemoveButton As System.Windows.Forms.Button

Friend WithEvents ExecuteButton As System.Windows.Forms.Button

Friend WithEvents SubFoldersCheckBox As System.Windows.Forms.CheckBox

Friend WithEvents Label1 As System.Windows.Forms.Label

Friend WithEvents PatternTextBox As System.Windows.Forms.TextBox

Friend WithEvents BindingSource1 As System.Windows.Forms.BindingSource

End Class

Form1.vb – This is the code that does the actual work

Public Class Form1

'Create a collection to hold each folder entry item

Private myFolders As List(Of FolderEntry)

'Declare a variable to hold the save file location

Private mySaveFile As String

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

'Build the save file location

mySaveFile = System.IO.Path.Combine(My.Application.Info.DirectoryPath, "folderlist.bin")

'If the save file exists, load it

If System.IO.File.Exists(Me.mySaveFile) Then

'Create a binary serilizer

Dim bf As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter

'Create a file stream

Dim fs As New System.IO.FileStream(Me.mySaveFile, IO.FileMode.Open)

'Deserialize the binary file into a List(of FolderEntry) object

Me.myFolders = CType(bf.Deserialize(fs), List(Of FolderEntry))

'Close the file stream

fs.Close()

Else

'If there is no save file, create a new List(Of FolderEntry) object

Me.myFolders = New List(Of FolderEntry)

End If

'Setup the binding for the listbox

Me.BindingSource1.DataSource = Me.myFolders

Me.FoldersListBox.DisplayMember = "Path"

Me.FoldersListBox.DataSource = Me.BindingSource1

End Sub

Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing

'When the form closes, save the List(Of FolderEntry) object

Dim bf As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter

Dim fs As New System.IO.FileStream(Me.mySaveFile, IO.FileMode.Create)

bf.Serialize(fs, Me.myFolders)

fs.Close()

End Sub

Private Sub BrowseButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BrowseButton.Click

'Allow the user to browse to a folder

If Me.FolderBrowserDialog1.ShowDialog = Windows.Forms.DialogResult.OK Then

Me.NewPathTextBox.Text = Me.FolderBrowserDialog1.SelectedPath

End If

End Sub

Private Sub AddButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AddButton.Click

'Add a new folder entry to the list

Me.BindingSource1.Add(New FolderEntry(Me.NewPathTextBox.Text, Me.SubFoldersCheckBox.Checked, Me.PatternTextBox.Text))

End Sub

Private Sub RemoveButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RemoveButton.Click

'Remove the selected folder entry from the list

If Me.FoldersListBox.SelectedIndex > -1 Then

Me.BindingSource1.Remove(Me.FoldersListBox.SelectedItem)

End If

End Sub

Private Sub ExecuteButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExecuteButton.Click

'Check each folder in the list

For Each fe As FolderEntry In Me.myFolders

Me.DeleteOldFiles(fe.Path, fe.IncludeSubFolders, fe.SearchPattern)

Next

MessageBox.Show("File check complete.", "Done", MessageBoxButtons.OK, MessageBoxIcon.Information)

End Sub

'Create a sub to delete the old files

'Tell the routine the path to delete from, whether to check sub directories, and what file names and/or types to delete

Private Sub DeleteOldFiles(ByVal path As String, ByVal includeSubDir As Boolean, Optional ByVal fileFilter As String = "*.*")

'Check if the path supplied exists

If System.IO.Directory.Exists(path) Then

'Get the search option based on the parameter

Dim opt As System.IO.SearchOption

If includeSubDir Then

opt = IO.SearchOption.AllDirectories

Else

opt = IO.SearchOption.TopDirectoryOnly

End If

'Get the list of files

Dim files() As String = System.IO.Directory.GetFiles(path, fileFilter, opt)

'Loop through each file name in the list

For Each f As String In files

'Get the creation time of the file

Dim created As Date = System.IO.File.GetCreationTime(f)

'If it was created more than 10 days ago...

If Now.Subtract(created).TotalDays > 10 Then

'Delete the file

System.IO.File.Delete(f)

End If

Next

Else

'If the path was invalid throw an exception that says so

Throw New ArgumentException("The path specified does not exist.")

End If

End Sub

End Class

'Create a simple class to hold each folder entry

'Mark it Serializable for easy saving

<Serializable()> _

Public Class FolderEntry

Private myPath As String

Private mySubFolders As Boolean

Private myPattern As String

Public Sub New()

MyBase.New()

End Sub

Public Sub New(ByVal path As String, ByVal subFolders As Boolean, Optional ByVal pattern As String = "*.*")

MyBase.New()

Me.myPath = path

Me.mySubFolders = subFolders

Me.myPattern = pattern

End Sub

Public Property Path() As String

Get

Return Me.myPath

End Get

Set(ByVal value As String)

Me.myPath = value

End Set

End Property

Public Property IncludeSubFolders() As Boolean

Get

Return Me.mySubFolders

End Get

Set(ByVal value As Boolean)

Me.mySubFolders = value

End Set

End Property

Public Property SearchPattern() As String

Get

Return Me.myPattern

End Get

Set(ByVal value As String)

Me.myPattern = value

End Set

End Property

End Class

That should give you something to work with/learn from.

Hope it helps! Good luck!!

rkimble at 2007-8-31 > top of Msdn Tech,Visual Basic,Visual Basic Language...