Getting counter to return correct number after being recursively called c#

Viewed 50

I have a method called clearFiles which can be called recursively if there is sub directories. I have created a counter that will count the number of files that have been deleted. The counter holds the correct number when the function is either called once or called recursively but the toast at the end of the function only returns the correct number when it is not called recursively. Is there anyway I can display the toast and then reset the number of filesCleared? Because it's just returning a 0 when it's called recursively. From playing around with it for a bit it seems like the toast is getting called after the filesCleared variable is set to 0 which is not what I want.

filesCleared variable:

    int filesCleared = 0;

clearFiles:

public async Task ClearFiles()
    {
        var pathName = FileFilter.PathName;
        FileInfo[] files = SortFiles(pathName);

        try
        {
            if(FileFilter.Filter == "all")
            {
                foreach(var file in files)
                {
                    if(file.Extension == FileFilter.Extension || FileFilter.Extension == "all")
                    {
                        File.Delete(file.ToString());
                        filesCleared++;
                    }

                }
            }

            if(FileFilter.Filter == "date")
            {            
                foreach (var file in files) //regular files
                {
                    if(file.CreationTime < FileFilter.DeleteDate) //based on time
                    {
                        if(file.Extension == FileFilter.Extension || FileFilter.Extension == "all") //based on extension
                        {
                            File.Delete(file.ToString());
                            filesCleared++;
                        }  
                    }

                }
            }

            if(FileFilter.Filter == "number")
            {
                var i = 0;

                for(var j = files.Length-1; j >= 0 ; j--)
                {
                    if(files[j].Extension == FileFilter.Extension || FileFilter.Extension == "all")
                    {
                        if(i++ >= FileFilter.FilesToKeep)
                        {
                            File.Delete(files[j].ToString()); 
                            filesCleared++;
                        }
                    }                        
                }

            }

            if (FileFilter.SubFolders == true) //subfiles (will be called recursively w/ each filter)
            {
                foreach(var subDir in new DirectoryInfo(pathName).GetDirectories())
                {
                    //subDir.Delete(true);
                    FileFilter.PathName = subDir.ToString();
                    ClearFiles();
                    //await ClearFiles(subDir.ToString()); 
                }  

                FileFilter.PathName = pathName; //resets the pathName so it will go back to what it was before the recursion 
            }          
        }
        catch (IOException ioExp)    
        {    
            Console.WriteLine(ioExp.Message);    
            Toast = Toast.Bad();
            logger.LogError(ioExp, "Error Deleting");
        }               

        Toast = Toast.Good(filesCleared + " Files Deleted");

        filesCleared = 0; 
    }
1 Answers

If you want to do something once but also want to call a method recursively, you have to split it in two. After trying to simplify your code I get a ClearFiles method like this:

public void ClearFiles()
{
    var filesCleared = 0;
    try
    {
        filesCleared = DeleteFilesRecursively(FileFilter.PathName, FileFilter);
    }
    catch (IOException ioExp)    
    {    
        Console.WriteLine(ioExp.Message);    
        Toast = Toast.Bad();
        logger.LogError(ioExp, "Error Deleting");
    }               

    Toast = Toast.Good(filesCleared + " Files Deleted");
}

Now Toast.Good is only called once after all subfolders have been traversed.

Note that filesCleared is a local variable, since I don't see any point in making it global. That way you also don't need to reset it.

The implementation of DeleteFilesRecursively could be something like this and could be simplified more if you wanted:

private const string All = "all";
private const string FilterByDate = "date";
private const string FilterByNumber = "number";

int DeleteFilesRecursively(string dirPath, SomeFileFilterType fileFilter)
{
    FileInfo[] files = SortFiles(dirPath);
    var deleted = 0;
    var toBeDeleted = files.Where(f => MatchesByExtension(f, fileFilter.Extension));

    if (fileFilter.Filter == FilterByDate)
    {            
        toBeDeleted = toBeDeleted.Where(f => MatchesByDate(f, fileFilter.DeleteDate));
    }
    else if (FileFilter.Filter == FilterByNumber)
    {
        // If your SortFiles method sorted in the other
        // direction this call to Reverse would not be needed.
        toBeDeleted = toBeDeleted.Reverse().Take(fileFilter.FilesToKeep);
    }
    
    foreach (var file in toBeDeleted)
    {
        File.Delete(file.ToString()); 
        deleted++;
    }

    if (fileFilter.SubFolders)
    {
        foreach(var subDir in new DirectoryInfo(dirPath).GetDirectories())
        {
            deleted += DeleteFilesRecursively(subDir.FullName, fileFilter);
        }
    }
    
    return deleted;
}

bool MatchesByExtension(FileInfo file, string extension)
    => file.Extension == extension || extension == All;

bool MatchesByDate(FileInfo file, DateTime deleteDate)
    => file.CreationTime < deleteDate;

Note that I also removed your magic strings, which could be even better by replacing them with an enum type.

I haven't tested this but I believe it should give you the same behavior as your current code (at least the parts about filtering and deleting).

Related