MrGoodbytes
MrGoodbytes

Reputation: 294

vb.net for each loop counter

I am trying to make a program to organize folders full of random stuff. I want it to put each file type into a folder that describes what it is in it. I have arrays of file types inside another array so it can loop through.

It can move the file types specified in the array fine, but when I tried to make it put each type into a seperate folder, it says that the array index is out of bounds.

It works fine if you replace the index of Names to a number, but i can't get it to change it automatically.

Here is the code I am using:

Dim Extensions As Array = {Audio, Video, Image, Document, PlainText, Batch, Powershell, VB, DiskImage, Compressed, Excutable, Model, Code, Web, Registry}
Dim Names As String() = {"Audio", "Videos", "Pictures", "Documents", "Text Documents", "Batch", "Powershell", "Visual Basic", "DiskImages", "Compressed Files", "Excutables", "3d Models", "Code", "Web", "Registry"}

    Dim number As Integer = 0
    For Each type As String() In Extensions
        number += 1
        path = path + Names(number)

        For Each extension As String In type
            Label2.Text = extension
            CopyMove(FolderBrowserDialog2.SelectedPath, path, extension, s)
        Next

    Next

Upvotes: 1

Views: 1970

Answers (2)

Darren S
Darren S

Reputation: 656

You primarily have three issues:

  1. Arrays are zero-based, so you should not add 1 to your number iterator until the end of the loop, otherwise Audio will go into "Videos" and videos will go into "Pictures" and eventually Registry will overflow the output path.
  2. In VB, you should use ampersand "&" when concatenating strings.
MsgBox(4 + 5)  ' output: 9
MsgBox(4 & 5)  ' output: 45
  1. These paired arrays are actually just "key-value pairs", there's a specific class in .Net for that called a dictionary, you should use it here:

A dictionary is basically like an array (it's a "collection") that instead of putting in a number as your key, you can put in a custom variable type of your choice (like a string!), so instead of trying to find the extensions number that matches a file extension, looking that up in an array then comparing that with another array, you can just say "give me the folderPath for an extension('.txt')", and it does all the pairing work for you.

Sample program with dictionary:

On your form create a "TextBox" which should be named "TextBox1" by default.

Find the property "MultiLine" and set it to true.

Make it bigger.

Source Code:

Public Class Form1

    ' List of file types that I want to sort
    Private fileFolders As New Dictionary(Of String, String) From {
        {".txt", "documents"},
        {".doc", "documents"},
        {".docx", "documents"},
        {".png", "images"},
        {".jpg", "images"},
        {".mp4", "videos"}
    }   ' TODO: Add more

    Private Sub MoveFiles(Optional sourceDirectory As String = "")

        TextBox1.Text = ""

        If sourceDirectory = "" Then sourceDirectory = "source"
        ' list of files to sort
        Dim files As String() = IO.Directory.GetFiles(sourceDirectory, "*.txt", IO.SearchOption.AllDirectories)

        If files.Length = 0 Then
            TextBox1.Text &= "No files were found in source directory!"
            Exit Sub
        End If

        Dim fileName As String
        Dim fileExtension As String
        Dim folderName As String
        For Each sourceFile As String In files
            fileName = IO.Path.GetFileName(sourceFile)
            fileExtension = IO.Path.GetExtension(sourceFile)

            ' set folderName to "misc" if I don't have an extension case in my dictionary to handle it:
            If fileFolders.ContainsKey(fileExtension) Then
                folderName = fileFolders(fileExtension) ' dictionary entry gets used here
            Else
                folderName = "misc"
            End If

            CheckCreateDirectory(folderName) ' creates folder if doesn't exist
            ' String interpolation is prettier than string concatenation and highly optimized, feel free to use it a lot,
            ' the syntax is dollar sign, opening quotes, literal string, insert variables in braces, closing quotes:
            TextBox1.Text &= $"Moving file: [{sourceFile}] to folder: [{folderName}]{Environment.NewLine}"
            IO.File.Move(sourceFile, fileFolders(folderName) & "\" & fileName)
        Next
    End Sub

    Private Sub CheckCreateDirectory(directoryName As String)
        If Not IO.Directory.Exists(directoryName) Then
            TextBox1.Text &= $"Folder: [{directoryName}] does not exist, creating folder" & vbCrLf
            IO.Directory.CreateDirectory(directoryName)
        End If
    End Sub

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        MoveFiles("source")
    End Sub
End Class

Create a folder in your compile/output directory named 'source' to test it on and add a file or two:

enter image description here

Run the program:

enter image description here

Directories should have been created and the files should have been sorted:

enter image description here

Upvotes: 0

Joel Coehoorn
Joel Coehoorn

Reputation: 415735

Paired arrays such as this are poor practice. Much better to create a class and then use a single array or List of that class:

Public Class FileType
    Public Property Category As String   
    Public Property Extensions As List(Of String)
End Class

Dim Filetypes As New List(Of FileType) From {
    New FileType() With {Category = "Audio", Extensions = Audio },
    New FileType() With {Cateogry = "Video", Extensions = Video }
    '...
} 


For Each type As FileType In FileTypes
    Dim thisPath As String = Path.Combine(path, type.Category)

    For Each extension As String In type.Extensions
        Label2.Text = extension ' this label won't update inside the method, but that's another question
        CopyMove(FolderBrowserDialog2.SelectedPath, thisPath, extension, s)
    Next
Next

Upvotes: 3

Related Questions