Joudicek Jouda
Joudicek Jouda

Reputation: 792

How to get progress while recursively crawling a directory structure?

I've got a function that loads all *.txt in given folder and all it's subfolders. I would like to get the actual progress (e.g. 15/35 loaded).

But I can't think of any way how to get the number of files which were loaded in a directory stucture one level below, to add to current index.

* a
  * b
     - 1.txt (file in dir b)
  - 1.txt (file in dir a)
  - 2.txt _(index of this file is 3 - one file from dir below, one file in this dir)_

Code:

    public int getFilesInSubfolders(directory)
    {
        int count = 0;

        foreach (subdirectory in directory)
        {
            count += getFilesInSubfolders();
        }

        foreach (txtfile in folderFiles)
        {

            load(txtfile);
            count++;

            updateProgress(actualIndex); // how to get the actual index? e.g. 15/35 loaded, so that 15
        }
        return count;
    }

Upvotes: 0

Views: 797

Answers (4)

Matthew Watson
Matthew Watson

Reputation: 109732

There are two ways of addressing this.

You could just pass a ref int count to each recursive call. The outermost call would initialise count to zero.

For example:

public int IterateDirectories(string root)
{
    int count = 0;
    iterateDirectories(root, ref count);
    return count;
}

private void iterateDirectories(string root, ref int count)
{
    foreach (string directory in Directory.EnumerateDirectories(root))
        iterateDirectories(directory, ref count);

    foreach (string file in Directory.EnumerateFiles(root, "*.txt"))
    {
        // load(file);

        ++count;

        // Now count is the actual number of files processed,
        // so you can use it for updateProgress()
    }
}

Alternatively, you can wrap the whole thing in a class like this:

public sealed class DirectoryIterator
{
    public static int Iterate(string root)
    {
        var iterator = new DirectoryIterator();
        iterator.iterate(root);
        return iterator.count;
    }

    private void iterate(string root)
    {
        foreach (string directory in Directory.EnumerateDirectories(root))
            iterate(directory);

        foreach (string file in Directory.EnumerateFiles(root, "*.txt"))
        {
            // load(file);

            ++count;

            // Now count is the actual number of files processed,
            // so you can use it for updateProgress()
        }
    }

    private int count;

    private DirectoryIterator(){}
}

Which you can use like this:

int count = DirectoryIterator.Iterate("D:\\");

(although you probably don't care about the returned value.)

You would need to modify this code for your exact purposes (it doesn't have the total count of files that you say you already have computed, so you'd have to add a field for that).

Note: I have omitted error handling from both those examples. Real code would have to avoid the protected system directories.

Upvotes: 2

Konstantin Chernov
Konstantin Chernov

Reputation: 1936

Obvious straightforward solution is to loop it twice - first counting the number of files and then using the counter to updateProgress. To make it more readable you can refactor it away from recursion, using the Stack<T> data-structure, but that's another story.

OK after your explanations I assume the following refactoring. You have actualIndex as soon as you don't use recursion.

int totalCounter = GetTheTotalTxtFilesNumber();//as you've mentioned you already have it

Stack<Directory> directoryStack = new Stack<Directory>();
  directoryStack.Push(directory);

  int actualIndex = 0;  
  while(directoryStack.Count > 0)
  {
    Dirextory current = directoryStack.Pop();  

    foreach (txtfile in folderFiles)
    {
       load(txtfile);
       actualIndex++;
       updateProgress(actualIndex);//15 out of 35
    }
    foreach (subdirectory in current )
    {
       directoryStack.Push(subdirectory );
    }
  }

Upvotes: 0

Symaps_Paul
Symaps_Paul

Reputation: 66

I can give you the 15 part in 15/35 but not the 35 part as I don't know that until the itteration is complete.

public int getFilesInSubfolders(directory, int count) {

    foreach (subdirectory in directory)
    {
       getFilesInSubfolders(subDirectory,count);
    }

    foreach (txtfile in folderFiles)
    {

        load(txtfile);
        count++;

        updateProgress(count); // how to get the actual index? e.g. 15/35 loaded, so that 15
    }
    return count;
}

Upvotes: 0

p.s.w.g
p.s.w.g

Reputation: 149030

I don't see why you have to use recursion for this. There is a convenient overload of Directory.GetFiles which allows you to get all files in all subfolders:

public int GetFilesInSubfolders(string directory)
{
    var files = Directory.GetFiles(directory, "*.txt", SearchOption.AllDirectories));
    for (var i = 0; i < files.Length; i++)
    {
        load(files[i]);
        updateProgress(i); 
    }

    return files.Length;
}

Upvotes: 0

Related Questions