I am looking for a way to list subfolders in a set folder using FOr loop. I got this for files in folder like:
For Each File As String In System.IO.Directory.GetFiles("G:\100 Databases\ASSETS\FLAGS\JPG\")
.Items.Add(System.IO.Path.GetFileNameWithoutExtension(File))
Next
But how does this would be for folders
For Each Folder As String In IO.Directory.GetDirectories(ClientsFolder)
.Items.Add(System.IO.Path.GetDirectoryName(Folder))
Next
My version just lists the ClientFolder subfolders number of times but not the actual subfolder name.
CodePudding user response:
The Path
class just works on Strings
. It doesn't know anything about actual files and folders. It just knows the conventions of file system paths. The GetFileName
method will simply get everything after the last "\"
delimiter, without distinguishing between file and folder paths. That's what you need to use:
.Items.Add(System.IO.Path.GetFileName(Folder))
That said, there are more improvements you can make to that code.
Firstly, you should generally only use a namespace to qualify a type once. If you would need to use the same namespace twice or more, import that namespace instead. You can import a namespace project-wide on the References page of the project properties or you can import it at the file level at the top of the code, e.g.
Imports System.IO
and then:
For Each Folder As String In Directory.GetDirectories(ClientsFolder)
.Items.Add(Path.GetDirectoryName(Folder))
Next
Next, it's generally preferable to make a single call to AddRange
than it is to make multiple calls to Add
. If you're adding individual items here and there then that's different but you should call AddRange
rather than Add
in a loop. It won't really make much, if any, difference in most cases but it's good to create good habits so you won't do the wrong thing when it does matter, e.g.
Dim folders = Directory.GetDirectories(clientsFolder)
For i = 0 To folders.getUpperBound(0)
folders(i) = Path.GetFileName(i)
Next
.Items.AddRange(folders)
Notice that I have also used a lower-case character to start variable names. You don't have to do that but it's what Microsoft recommends and it's what the bulk of .NET developers do.
Next, it is often preferable to bind a list to a ComboBox
rather than add items directly. For a simple list, it doesn't make too much difference, but it may be advantageous here. What you can do it use DirectoryInfo
objects instead of simple Strings
. You can then display the Name
property, which is just the folder name, but still have access to the FullName
property, which is the full path, e.g.
Dim clientsFolder = New DirectoryInfo(clientsFolderPath)
Dim subFolders = clientsFolder.GetDirectories()
.DisplayMember = NameOf(DirectoryInfo.Name)
.ValueMember = NameOf(DirectoryInfo.FullName)
.DataSource = subFolders
When the user selects a folder name, you can then get its full path from the SelectedValue
property of the ComboBox
.
If you're doing this for files rather than folders then there is a FileInfo
class that has the same properties, but it doesn't have a property that will remove the file extension. You can throw a bit of LINQ at the problem though, and make your own, e.g.
Dim filePaths = Directory.GetFiles(clientsFolderPath)
.DisplayMember = "NameWithoutExtension"
.ValueMember = "FullPath"
.DataSource = filePaths.Select(Function(s) New With {.FullPath = s, .NameWithoutExtension = Path.GetFileNameWithoutExtension(s)}).ToArray()
More to follow...