很抱歉各位看官,不太会排版丑陋了点,但是重点很清晰。
因本人的工作原因,大部分时间都在和控制台打交道,话说无论写什么控制台处理程序都有进度显示,方便直观。假设如果仅使用文件方式记录进度的话相当的麻烦,当然这个用作记录日志的话另当别论了。本文为了方便查看处理进度而特意在ConsoleApplication ProgressBar花了1个小时而开发的一个进度条控件类。
首先例举两个个常用的记录进度方式:
1、Console.Write
如图:
这种是最常见的,没什么好不好之说,但是不好的地方显而易见:屏幕一刷而过,当有其他的信息需要打印的时候还得翻滚动条。如果进度太长就无奈了。
2、Console.Title
如图:
这个用的相对比较少,如果开的比较多控制台的话,Title上原本的信息就没有了。
3、ConsoleApplication ProgressBar
如图:
综合前面两种方式,后者是最为方便的。好处我想不用我多说了。
下面奉上源码
调用示例:
class Program { static void Main( string[] args) { Random r = new Random(); while ( true) { ConsoleProgressBar bar = new ConsoleProgressBar( " 测试ConsoleApplication ProgressBar "); int c = r.Next( 534); for ( int i = 1; i <= c; i++) { bar.Update(i, c, string.Format( " 完成进度:{0}/{1} ", i, c)); System.Threading.Thread.Sleep( 10); } // 等待退出 Console.ReadKey( true); } } }
源码:
public class ConsoleProgressBar { int left = 0; int backgroundLength = 50; #region [ window api ] ConsoleColor colorBack = Console.BackgroundColor; ConsoleColor colorFore = Console.ForegroundColor; private const int STD_OUTPUT_HANDLE = - 11; private int mHConsoleHandle; COORD barCoord; [StructLayout(LayoutKind.Sequential)] public struct COORD { public short X; public short Y; public COORD( short x, short y) { X = x; Y = y; } } [StructLayout(LayoutKind.Sequential)] struct SMALL_RECT { public short Left; public short Top; public short Right; public short Bottom; } [StructLayout(LayoutKind.Sequential)] struct CONSOLE_SCREEN_BUFFER_INFO { public COORD dwSize; public COORD dwCursorPosition; public int wAttributes; public SMALL_RECT srWindow; public COORD dwMaximumWindowSize; } [DllImport( " kernel32.dll ", EntryPoint = " GetStdHandle ", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern int GetStdHandle( int nStdHandle); [DllImport( " kernel32.dll ", EntryPoint = " GetConsoleScreenBufferInfo ", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern int GetConsoleScreenBufferInfo( int hConsoleOutput, out CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo); [DllImport( " kernel32.dll ", EntryPoint = " SetConsoleCursorPosition ", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern int SetConsoleCursorPosition( int hConsoleOutput, COORD dwCursorPosition); public void SetCursorPos( short x, short y) { SetConsoleCursorPosition(mHConsoleHandle, new COORD(x, y)); } public COORD GetCursorPos() { CONSOLE_SCREEN_BUFFER_INFO res; GetConsoleScreenBufferInfo(mHConsoleHandle, out res); return res.dwCursorPosition; } #endregion public ConsoleProgressBar( string title, int left = 10) { Console.WriteLine(); // 获取当前窗体句柄 mHConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE); // 获取当前窗体偏移量 barCoord = this.GetCursorPos(); this.left = left; // 获取字符长度 int len = GetStringLength(title); // 设置标题的相对居中位置 Console.SetCursorPosition(left + (backgroundLength / 2 - len), barCoord.Y); Console.Write(title); // 写入进度条背景 Console.BackgroundColor = ConsoleColor.DarkCyan; Console.SetCursorPosition(left, barCoord.Y + 1); for ( int i = 0; ++i <= backgroundLength; ) Console.Write( " "); Console.WriteLine(); Console.BackgroundColor = colorBack; } /// <summary> /// 更新进度条 /// </summary> /// <param name="current"> 当前进度 </param> /// <param name="total"> 总进度 </param> /// <param name="message"> 说明文字 </param> public void Update( int current, int total, string message) { // 计算百分比 int i = ( int)Math.Ceiling(current / ( double)total * 100); Console.BackgroundColor = ConsoleColor.Yellow; Console.SetCursorPosition(left, barCoord.Y + 1); // 写入进度条 StringBuilder bar = new StringBuilder(); // 当前百分比*进度条总长度=要输出的进度最小单位数量 int count = ( int)Math.Ceiling(( double)i / 100 * backgroundLength); for ( int n = 0; n < count; n++) bar.Append( " "); Console.Write(bar); // 设置和写入百分比 Console.BackgroundColor = colorBack; Console.ForegroundColor = ConsoleColor.Green; Console.SetCursorPosition(left + backgroundLength, barCoord.Y + 1); Console.Write( " {0}% ", i); Console.ForegroundColor = colorFore; // 获取字符长度 int len = GetStringLength(message); // 获取相对居中的message偏移量 Console.SetCursorPosition(left + (backgroundLength / 2 - len), barCoord.Y + 2); Console.Write(message); // 进度完成另起新行作为输出 if (i >= 100) Console.WriteLine(); } /// <summary> /// 获取字符长度 /// </summary> /// <remarks> 中文和全角占长度1,英文和半角字符2个字母占长度1 </remarks> /// <param name="message"></param> /// <returns></returns> private int GetStringLength( string message) { int len = Encoding.ASCII.GetBytes(message).Count(b => b == 63); return (message.Length - len) / 2 + len; } }