Geeks With Blogs

News

Currently Reading

CLR via C#m
Under The Influence(of code) Abhijeet Patel's blog

 

 

Showing the progress of an operation is trivial in rich client applications using a progress bar control of some sort. But what about .NET console apps? The Console class offers 2 static methods Console.Write and Console.WriteLine to write out to the Console, but any subsequent calls to these methods will write the content out at the current location of the cursor.This doesn't really help when you want the progress percentage to refresh in place instead. The trick is to write out the "\r" character in the call to Console.Write so that the cursor is repositioned to the begining of the line after the content is written out. Following is quick implementation of a method which shows percentage of progress, refreshing the percent value in place.

 

 
  1. static void ShowPercentProgress(string message, int currElementIndex, int totalElementCount)   
  2. {   
  3.     if (currElementIndex < 0 || currElementIndex >=totalElementCount)   
  4.     {   
  5.            throw new InvalidOperationException("currElement out of range");   
  6.     }   
  7.     int percent =  (100 * (currElementIndex + 1)) / totalElementCount;   
  8.     Console.Write("\r{0}{1}% complete",message, percent);   
  9.     if (currElementIndex == totalElementCount-1)   
  10.     {   
  11.         Console.WriteLine(Environment.NewLine);   
  12.     }   
  13. }  

and the caller of course.
 

 
  1. static void Main(string[] args)   
  2. {   
  3.   
  4.     for (int i = 0; i < 100; i++)   
  5.     {   
  6.         ShowPercentProgress("Processing...", i, 100);   
  7.         Thread.Sleep(100);   
  8.     }   
  9. }  

That's all there is to it. Happy coding.

UPDATE: This example wouldn't be complete unless I provide an Python implmentation since that's what I'm living and breathing these days.

 

 
  1. def showProgress(message, it = [], currElement = 0):   
  2.     percent = (100 * (currElement + 1)) / len(it)   
  3.     sys.stdout.write("\r")   
  4.     sys.stdout.write("%s %i complete" % (message, percent))   
  5.     sys.stdout.flush()   
  6.   
  7. def process(it, notifyCompletion = showProgress):   
  8.     for item in it:   
  9.         time.sleep(0.5)   
  10.         notifyCompletion("Processing", it, it.index(item))            
  11.   
  12. if __name__ == "__main__":      
  13.     process(range(10));   

UPDATE(4/27/11): I received a comment requesting a precise usage example of the above for copying files
The code below has been adapted to achieve that.
Disclamer: If you use this code, please add proper error handling as you see fit.

 

 
  1. class Program   
  2. {    
  3.        static void Copyfiles(   
  4.             string[] sourceFiles,   
  5.             string destPath,                
  6.             Action<string,long,long> reportProgress,   
  7.             int blockSizeToRead = 4096)   
  8.         {               
  9.             if(!Directory.Exists(destPath))   
  10.             {   
  11.                throw new DirectoryNotFoundException(destPath);   
  12.             }   
  13.             foreach (var sourceFile in sourceFiles)   
  14.             {   
  15.                 if (!File.Exists(sourceFile))   
  16.                 {   
  17.                     Console.WriteLine("{0} not found.. skipping",sourceFile);   
  18.                 }   
  19.                 FileInfo sourceFileInfo = new FileInfo(sourceFile);   
  20.                 string message = string.Format("Copying {0} ", sourceFileInfo.Name);   
  21.                 string destFilePath = Path.Combine(destPath, sourceFileInfo.Name);   
  22.                 byte[] buffer = new byte[blockSizeToRead];   
  23.                 using (var destfs = File.OpenWrite(destFilePath))   
  24.                 {   
  25.                     using (var sourcefs = File.OpenRead(sourceFile))   
  26.                     {                           
  27.                         int bytesRead,totalBytesRead = 0;   
  28.                         while ((bytesRead = sourcefs.Read(buffer, 0, buffer.Length - 1)) > 0)   
  29.                         {   
  30.                             destfs.Write(buffer, 0, bytesRead);   
  31.                             totalBytesRead += bytesRead;   
  32.                             if (reportProgress != null)   
  33.                             {   
  34.                                 reportProgress(message, totalBytesRead, sourceFileInfo.Length);   
  35.                             }   
  36.                         }   
  37.                     }   
  38.                 }   
  39.             }   
  40.         }   
  41.   
  42.         static void ShowPercentProgress(string message, long processed, long total)   
  43.         {   
  44.                
  45.             long percent = (100 * (processed + 1)) / total;   
  46.             Console.Write("\r{0}{1}% complete", message, percent);   
  47.             if (processed >= total - 1)   
  48.             {   
  49.                 Console.WriteLine(Environment.NewLine);   
  50.             }   
  51.         }     
  52.         static void Main(string[] args)   
  53.         {   
  54.             var files = Directory.GetFiles(@"C:\temp\source");   
  55.             Copyfiles(files, @"C:\temp\dest", ShowPercentProgress);   
  56.         }   
  57. }  

 

 

Posted on Sunday, February 21, 2010 10:50 AM C# | Back to top


Comments on this post: Showing Progress in a .NET Console Application

# re: Showing Progress in a .NET Console Application
Requesting Gravatar...
Interesting indeed my friend! :)

I am glad C# "behaves" similarly to the python counterpart, I wonder if t all depends on the actual implementation of the "console" (cmd.exe), which nowadays is a mere simulation of what a "DOS" window used to be..., in any case, when we finally switch to windows 7 t work (I know, I dream too much), It'll be interesting to see if both samples behave the same (i.e. interpret the control codes properly, etc). In the Linux world you have the ncurses library which makes command control an easy task, but I am yet to see a Win32 implementation of it.. Thanks for the post, pretty interesting.
Left by Julio Schwarzbeck on Feb 21, 2010 1:33 PM

# re: Showing Progress in a .NET Console Application
Requesting Gravatar...
Hi,
can you give us a more precise usage example, like copying 4 files using your progress tool, please?
Left by Joe on Apr 27, 2011 2:57 AM

# re: Showing Progress in a .NET Console Application
Requesting Gravatar...
@Joe: I've updated the post to show progress for copying of files.
Hope this helps.

-Abhijeet
Left by Abhijeet on Apr 27, 2011 10:05 PM

# re: Showing Progress in a .NET Console Application
Requesting Gravatar...
Thanks for the example. will test it and let you know.

Cheers !
Left by Joe on Apr 28, 2011 2:26 AM

# re: Showing Progress in a .NET Console Application
Requesting Gravatar...
Your code samples helped me solve a progress-bar problem I've had for days! Thanks!
Left by Alan8 on Dec 12, 2012 1:50 PM

Your comment:
 (will show your gravatar)


Copyright © Abhijeet Patel | Powered by: GeeksWithBlogs.net