views:

374

answers:

6

So, I'm doing a simple scan to get a list of all folders on a hard drive (c:\windows and c:\windows\system32 are considered separate entries). If I wanted to provide a progress bar for this 1-2 minute task, how would I do so? That is, I know how to make the progressbar but am not sure how to determine how much of the work for it is done.

Edit: Note that performing a prescan is NOT a solution, since this scan is only getting a list of folders and a prescan would take just as long.

Code Sample is below. It takes under 2 minutes to run clean on my system, but less than 10s to run a 2nd time due to disk access caching. I've created variations on this that are stack-based rather than recursion based.

One mechanism I've found that is probably not 100% reliable but is much faster than my scan is to pipe "dir/s/ab/b" to my program and count instances of newline. Dir does some sort of magic that does a much better job scanning my HD than my program, but I don't know what that magic is.

class Program
{
    static void recurse(string pos)
    {
        DirectoryInfo f = new DirectoryInfo(pos);
        try
        {
            foreach (DirectoryInfo x in f.GetDirectories("*"))
            {
                recurse(x.FullName);
            }
        } catch (Exception) {}
    }
    static void Main(string[] args)
    {
        recurse("c:\\");
    }
}
+2  A: 

Just don't use it. Try something more appropriate like spinning animation or Kitts style bar: http://en.wikipedia.org/wiki/KITT.

Jacek Ławrynowicz
+1  A: 

You can do it in a few ways....a simple process that might not be 100% accurate.

Before you start, get a count of files, then use that to calculate the percentage of completion, after processing X files update the progress. Granted there is a performance cost of the lookup. Maybe just get a count of root directories, and as you traverse update the progress.

Another option might be to simply record a count of "last run" details, and use that to calculate a percentage, again, not necessarily 100% accurate, but an option.

I guess a few other things that come to mind is to simply show the user a "in progress" dialog and not even try to get a percentage. Otherwise, maybe just show the current working directory, showing that you are making progress.

Mitchel Sellers
As I said, all this scan is doing is getting a list of folders. Any solution like what you proposed would take just as long as my scan.
Brian
Assuming you are using something like .NET, you would likely be able to use something like DirectoryInfo.GetDirectories(String, SearchOption), and then use the count of the returned collection. So it should be near instant...
Geoffrey Chetwood
Rich: No, because I'm getting ALL directories. If your solution worked, I'd just use *THAT* function for my scan.
Brian
@Brian - I think this begs the question of what you are doing then. Creating a list of folders should not take that long to complete. I have a system that parses 15,000 files in 1000 folders performing logic and disk writes on each, and it runs in 15 seconds.
Mitchel Sellers
@Brian - Can you add a code sample, or give us an idea of what you are doing in your code?
Mitchel Sellers
I also am confused as to how this solution is better than just doing the scan in the first place.
@belgariontheking - doing this to get a count SHOULDN'T take minutes to run....period. There must be something else being done.
Mitchel Sellers
Well, the code sample above takes 90s or so to run. I'll happily alter it if you wish. I should point out that I have A LOT of stuff on my machine, including a very dense winsxs directory thanks to Vista's magic.
Brian
A: 

If you can't recurse the directory structure since that would take as long as performing the task in the first place, the best you can do is guess how many folders there are. Seriously.

Perhaps you can use an algorithm based on past history (e.g. the last time I did this there were 150 directories in total when there were 10 top-level directories, therefore a good guess would be 15 times the current number of top-level directories).

Another way to tell a user something is going to take a while (without knowing exactly how long) is to use a countdown timer. Even if you've guessed that something will take longer than it actually will (say 5 minutes when it's really a 3-minute task), at least the user knows roughly how long it's going to take. And they'll be happier when it finishes faster than they were told it would. The only bummer, of course, is if you guess wrong on the other side, i.e. if something takes longer than you thought it would. Then they're sitting there waiting for something to finish that (in their mind) should have finished already.

Michael Todd
I think you mean 15 times.
A: 

You can create a progress bar with incrementing Maximum & Value properties. If you have your Maximum property initially set at 100, on your Timer's Tick event, increment both your Maximum & Value by 1 for example so you'll have values listed below...

         Maximum    Value 
Tick1:    101          1   - 1% 
Tick2:    102          2   - 2%
Tick3:    103          3   - 3% 
TickN:    100+n        n 
Finish    100+n      100+n - 100%  --> force to fill the progress bar

You can experiment on your initial Maximum value to have the progress bar move smoother.

Leon Tayson
+8  A: 

If you need to make a progress bar and you can't spare the time it takes to gather accurate information, then you're not going to be able to make a perfect progress bar. With that assumption in mind, you can still make a progress bar that isn't completely inaccurate.

For example, you make a function that subdivides the progress bar depending on the number of subdirectories in the current directory. So if your root directory has 10 subdirectories, allocate 10% of the progress bar to each of those directories. Then, enter into the first subdirectory and count its subdirectories. If it has 5, allocate 20% of the first 10% of the progress bar to each of those (2% of the total progress bar). Continue like this until you reach a directory with no subdirectories, do your processing there and increase the progress bar whatever fractional amount it represents.

Each % on the progress bar won't represent the same amount of work done by the algorithm, but given your contraints I doubt you can do much better.

Welbog
I suspected something like this would be the best I could do :/
Brian
+1  A: 

I tried grabbing the stdoutput of "dir/ad/b/s c:/" and counting the number of lines. This is pretty fast. It's trustworthy enough for use in a progressbar but not trustworthy enough for use as a list of directories.

Brian