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);
    } }
    /// <summary>
    /// 覆写
    /// </summary>
    /// <param name="context"></param>
    public static void OverWrite(string context = null)
    {
    lastContext = context;//记录上次写的内容
    var strLen = context?.Length ?? 0;
    //空白格的长度,考虑到内容可能超出一行的宽度,所以求余。
    var blankLen = Console.WindowWidth - strLen % Console.WindowWidth - 1;
    var rowCount = strLen / Console.WindowWidth;
    Console.SetCursorPosition(0, Console.CursorTop - rowCount);
    //空白只需填充最后一行的剩余位置即可。
    lock (_lock)
    {
    Console.Write(context + new string(' ', 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 - 1));
    Console.SetCursorPosition(0, currentLineCursor);
    }
    }

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

    static void Main(string[] args)
    {
    Console.WriteLine("Hello World!"); var task1 = Task.Run(() =>
    {
    int count = 0, w, lw, rw;
    float p = 0;
    while (true)
    {
    w = (int)(Console.WindowWidth * 0.6);
    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 中通用。为了保证输出的有序性,程序中加了锁,影像了多线程的效率,但是对于界面显示是足够的。如果需要高性能,那么考虑使用类似于队列式的异步更新输出显示的方法。

c# 控制台console进度条的更多相关文章

  1. Python 控制台进度条的实现

    进行爬虫等耗时的任务时,有时会想在控制台输出进度条,以显示当前任务进度.这里总结了两种方法. 方法1:使用tqdm模块 示例代码: from time import sleep from tqdm i ...

  2. 用C#实现控制台进度条

    在写一些简单的控制台测试程序时,经常希望能够在程序运行的过程中实现进度条的功能以便查看程序运行的速度或者进度.本文以C#为例,实现简单的控制台进度条,以供大家参考(本文底部附下载地址). 1.实现效果 ...

  3. [c#]控制台进度条的示例

    看到[vb.net]控制台进度条的示例 感觉很好玩,翻译成C#版. using System; using System.Collections.Generic; using System.Linq; ...

  4. [golang]golang如何覆盖输出console,实现进度条;golang一个骚气的进度提示库

    [golang]golang如何覆盖输出console,实现进度条 package main import( "fmt" "os" "time&quo ...

  5. 小技巧:with用法 pycharm控制台输出带颜色的文字 打印进度条的

    with用法 with用法在python中是一个很独特的用法,因为别的语言的中没有这个用法.所以针对这个特点我们来做一次总结,什么样的情况下可以同with  我们学到的有文件的操作,和acquire  ...

  6. ruby 编写控制台进度条

    ruby 中,$stdout.flush 让控制台当前行内容可以重写,以此我们可以做出进度条的效果. def set_progress(index, char = '*') print (char * ...

  7. 《C/C++实现Console下的加载进度条模拟[美观版]》

    前言   有时候我们会遇到在CMD或DOS控制台上出现的加载进度条,虽然不是如网页和软件写的美观.但确确实实也有着自己的特色.而且,一个好看的加载进度条也能增加用户使用控制台程序的体验!所以,拿来研究 ...

  8. Python中如何写控制台进度条的整理

    本文实例讲述了Python显示进度条的方法,是Python程序设计中非常实用的技巧.分享给大家供大家参考.具体方法如下: 首先,进度条和一般的print区别在哪里呢? 答案就是print会输出一个\n ...

  9. Ajax上传文件进度条显示

    要实现进度条的显示,就要知道两个参数,上传的大小和总文件的大小 html5提供了一个上传过程事件,在上传过程中不断触发,然后用已上传的大 小/总大小,计算上传的百分比,然后用这个百分比控制div框的显 ...

随机推荐

  1. vue-cli的服务代理

    vue-cli的默认端口是8080,如果我们的请求如下 我们就可以将地址改成

  2. CentOS7搭建LNMP环境

    以前写的过时了,重新发一篇新的. 安装PHP 下载官网:https://www.php.net/downloads.php 为了方便,我存了现成的 百度网盘:https://pan.baidu.com ...

  3. 每日一问:谈谈 SharedPreferences 的 apply() 和 commit()

    SharedPreferences 应该是任何一名 Android 初学者都知道的存储类了,它轻量,适合用于保存软件配置等参数.以键值对的 XML 文件形式存储在本地,程序卸载后也会一并清除,不会残留 ...

  4. Codeforces Gym100543L:Outer space invaders(区间DP)

    题目链接 题意 有n个人,每个人有一个出现时间a和一个开枪时间b和一个距离d,在任意一个时刻,你可以选择炸人,你要炸一个人的花费是和他的距离d,并且所有的已经出现并且还没开枪的和你距离<=d的人 ...

  5. 工具资源系列之给 windows 虚拟机装个 mac

    众说周知,Mac 很好但也很贵,对一般大众而言,漂亮简洁高颜值,对软件开发者而言,方便省心有点贵. 好到什么程度? 内置大量常用的开发工具,省去了初学者安装配置环境的麻烦,版本控制工具 svn 默认已 ...

  6. shell_umask用法

    我曾经用touch命令创建一个文件script,默认的权限是"rw-r- -r- -",有的朋友就有可能问为什么是这种组合?其实,这正是umask命令捣的鬼.在linux上输入:u ...

  7. 【译】.NET Core 3.0 发布自包含单体可执行程序

    .NET Core 提供的发布应用程序选项 self-contained 是共享应用程序的好方法,因为应用程序的发布目录包含所有组件.运行时和框架.您只需要告诉使用者应用程序的入口 exe 文件,就可 ...

  8. 【最小生成树之Prim算法】-C++

    [最小生成树之Kruskal算法] 没有看过的可以先看↑,会更简单. [模板]最小生成树 这一篇博客主要是介绍另外一种算法:Prim算法. prim算法就好像是一棵"生成树"在慢慢 ...

  9. 注入攻击-XSS攻击-CSRF攻击

    1.注入攻击 注入攻击包括系统命令注入,SQL注入,NoSQL注入,ORM注入等 1.1攻击原理 在编写SQL语句时,如果直接将用户传入的数据作为参数使用字符串拼接的方式插入到SQL查询中,那么攻击者 ...

  10. sudo ln -sf libhiredis.so.0.10 libhiredis.so.0

    which ldconfig sudo ln -sf libhiredis.so.0.10 libhiredis.so.0