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. django-haystack+whoosh+jieba实现中文全文搜索

    先上效果图 附上个人网站:https://liyuankun.cn 安装依赖库 注意:这里我们不安装django-haystack,因为要添加中文分词的功能很麻烦,所以我直接集成了一个中文的djang ...

  2. DFS(一):深度优先搜索的基本思想

    采用搜索算法解决问题时,需要构造一个表明状态特征和不同状态之间关系的数据结构,这种数据结构称为结点.不同的问题需要用不同的数据结构描述. 根据搜索问题所给定的条件,从一个结点出发,可以生成一个或多个新 ...

  3. Azkaban 3.73.1 集群搭建(Multiple Executor)

    一.简介 Azkaban是LinkedIn开源的任务调度框架,采用java编写 Azkaban功能和特点: 任务的依赖处理 任务监控,失败告警 任务流的可视化 任务权限管理 Azkaban具有轻量可插 ...

  4. mac-VBox-Centos6.6安装增强功能

    1. 更新内核 yum update kernel 2.安装依赖包 yum install kernel-headers yum install kernel-devel yum install gc ...

  5. 前端Web浏览器基于Flash如何实时播放监控视频画面(前言)之流程介绍

    [关键字:前端浏览器如何播放RTSP流画面.前端浏览器如何播放RTMP流画面] 本片文章只是起到抛砖引玉的作用,能从头到尾走通就行,并不做深入研究.为了让文章通俗易懂,尽量使用白话描述. 考虑到视频延 ...

  6. POI自动调整列宽支持中文

    /** * @Description:表格自适应宽度(中文支持) * @Author: * @param sheet sheet * @param columnLength 列数 */ private ...

  7. STL库的应用

    容器分为两类:序列式容器和关联式容器. 序列式容器,其中的元素不一定有序,但都可以被排序.如:vector.list.deque.stack.queue.heap.priority_queue.sli ...

  8. 消息队列(MQ)

    什么是消息队列 消息队列,即MQ,Message Queue. 消息队列是典型的:生产者.消费者模型.生产者不断向消息队列中生产消息,消费者不断的从队列中获取消息.因为消息的生产和消费都是异步的,而且 ...

  9. IO流簡單代碼

    今天測試了一下,在博客園裏HTML源碼編譯器裏寫CSS内部樣式,更新編譯后,内部樣式可用,但是會將寫的内部樣式代碼强制加上代碼注釋進行編譯,有點類似于强制注入.編譯后的效果就是在前面加入了一個空的p標 ...

  10. Nginx+Lua+MySQL/Redis实现高性能动态网页展现

    Nginx结合Lua脚本,直接绕过Tomcat应用服务器,连接MySQL/Redis直接获取数据,再结合Lua中Template组件,直接写入动态数据,渲染成页面,响应前端,一次请求响应过程结束.最终 ...