博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
c# 控制台console进度条
阅读量:6934 次
发布时间:2019-06-27

本文共 3822 字,大约阅读时间需要 12 分钟。

1 说明

笔者大多数的开发在 Linux 下,多处用到进度条的场景,但又无需用到图形化界面,所以就想着弄个 console 下的进度条显示。

2 步骤

  1. 清行显示

    //清行处理操作int currentLineCursor = Console.CursorTop;//记录当前光标位置Console.SetCursorPosition(0, Console.CursorTop);//将光标至于当前行的开始位置Console.Write(new string(' ', Console.WindowWidth));//用空格将当前行填满,相当于清除当前行Console.SetCursorPosition(0, currentLineCursor);//将光标恢复至开始时的位置

    如果要清除上一行,只需在清行处理操作前将调整光标位置提前一行,即:Console.SetCursorPosition(0, Console.CursorTop - 1);。紧接着Console.WriteLine(/*something*/);,即可实现在控制台末尾行重复输出。

  2. 多线程下的输出显示

    多线程下最容易出现的问题就是一个线程的输出覆盖其他线程的输出,或者是一个线程紧跟着上一个线程输出而没有换行,这些情况多会导致输出的混乱。为了,解决这样的问题,特意实现一个专门的输出类来进行输出显示:

    public class Consoler {     private static string lastContext = "";//用于记录上次写的内容     private static readonly object _lock = new object();//加锁保证只有一个输出     public static void Write(string context)     {         lastContext = context;//记录上次写的内容         lock (_lock)         {             Console.Write(context);         }     }     ///      /// 覆写     ///      ///      public static void OverWrite(string context = null)     {         lastContext = context;//记录上次写的内容         var strLen = context?.Length ?? 0;         //空白格的长度,考虑到内容可能超出一行的宽度,所以求余。         var blankLen = strLen % Console.WindowWidth;         Console.SetCursorPosition(0, Console.CursorTop);         //空白只需填充最后一行的剩余位置即可。         lock (_lock)         {             Console.Write(context + new string(' ', Console.WindowWidth - blankLen));         }     }     public static void WriteLine(string context = null)     {         ClearConsoleLine();//清除最后一行         lock (_lock)         {             Console.WriteLine(context);             if (!string.IsNullOrWhiteSpace(lastContext))                 Console.Write(lastContext);//重新输出最后一次的内容,否则有较明显的闪烁             lastContext = null;         }     }     public static void ClearConsoleLine(int invertedIndex = 0)     {         int currentLineCursor = Console.CursorTop;         int top = Console.CursorTop - invertedIndex;         top = top < 0 ? 0 : top;         Console.SetCursorPosition(0, top);         Console.Write(new string(' ', Console.WindowWidth));         Console.SetCursorPosition(0, currentLineCursor);     } }

    实际测试时,使用多 Task (模拟多线程)去进行输出实验:

    static void Main(string[] args) {     Console.WriteLine("Hello World!");     var task1 = Task.Run(() =>     {         int count = 0, w = (int)(Console.WindowWidth * 0.6), lw = 0, rw = 0;         float p = 0;         while (true)         {             count %= 75;             p = count++ / 74f;             lw = (int)(p * w);             rw = w - lw;             Consoler.OverWrite($"from task1, [{new string('#', lw) + new string(' ', rw)}]:{p:#.00%}");             Thread.Sleep(100);         }     });     var task2 = Task.Run(() =>     {         while (true)         {             Consoler.WriteLine($"from task2, now:{DateTime.Now}");             Thread.Sleep(5000);         }     });     var task3 = Task.Run(() =>     {         var rd = new Random();         while (true)         {             Consoler.WriteLine($"from task3, {new string('+', (int)(rd.NextDouble() * Console.WindowWidth))}");             Thread.Sleep(rd.Next(5000));         }     });     Task.WaitAll(task1); }

    最终输出结果:

    from task2, now:6/5/19 8:10:24 PM from task3, +++++++++++++++++++++++++++++++++ from task2, now:6/5/19 8:10:29 PM from task3, +++++++++++++++++++++++++ from task3, ++++ from task2, now:6/5/19 8:10:34 PM from task3, +++++++++++++++++++++++ from task3, ++++++++++++ from task3, ++++++ from task2, now:6/5/19 8:10:44 PM from task1, [###########################                     ]:58.11%

    task1 用来进行进度条的输出,task2 和 task3 进行随机输出。可以看出,task1 永远在最后一行进行进度更新,其他输出任然可以正常进行。实现的效果和 ubuntu 下执行更新命令sudo apt-get update的输出类似。

  3. 总结

    虽然该例子是在 c#下完成的,但在 python,c,java 中通用。为了保证输出的有序性,程序中加了锁,影像了多线程的效率,但是对于界面显示是足够的。如果需要高性能,那么考虑使用类似于队列式的异步更新输出显示的方法。

转载于:https://www.cnblogs.com/hsxian/p/10975784.html

你可能感兴趣的文章
/etc/resolv.conf
查看>>
Rstudio设置永久工作路径
查看>>
Objc基础学习记录3
查看>>
flask 学习app代码备份
查看>>
association classmethods
查看>>
jvm 内存分配 (转)
查看>>
[eclipse]的快捷键的设置
查看>>
数据结构和算法学习总结01 绪论
查看>>
js 的post提交的写法
查看>>
hadoop的dfs.replication
查看>>
redis基础_redis的安装
查看>>
C++学习总结 复习篇2
查看>>
使用VirtualPathUtility.ToAppRelative注意项
查看>>
博客编写计划
查看>>
大白话Vue源码系列(03):生成AST
查看>>
Android使用通讯录的权限问题
查看>>
ubuntu14.04安装chrome
查看>>
第七周
查看>>
Winform 打开下载的文件
查看>>
Java Web(一)需要掌握哪些东西
查看>>