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. Python程序中的协程操作-gevent模块

    目录 一.安装 二.Gevent模块介绍 2.1 用法介绍 2.2 例:遇到io主动切换 2.3 查看threading.current_thread().getName() 三.Gevent之同步与 ...

  2. TCP/IP网络协议

    OSI七层模型 OSI采用了分层的结构化技术,共分七层,物理层.数据链路层.网络层.传输层.会话层.表示层.应用层. TCP/IP模型 OSI模型比较复杂且学术化,所以我们实际使用的TCP/IP模型, ...

  3. 浅入深出Vue:第一个页面

    今天正式开始入门篇,也就是实战了~ 首先我们是要做一个博客网站,UI 框架采用江湖传闻中的 ElementUI,今天我们就来利用它确定我们博客网站的基本布局吧. 准备工作 新建一个vue项目(可以参考 ...

  4. redis源码笔记-内存管理zmalloc.c

    redis的内存分配主要就是对malloc和free进行了一层简单的封装.具体的实现在zmalloc.h和zmalloc.c中.本文将对redis的内存管理相关几个比较重要的函数做逐一的介绍 参考: ...

  5. scala刷LeetCode--26 删除排序数组中的重复项

    一.题目描述 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完 ...

  6. Jenkins部署Web项目到远程tomcat

    1.填加插件Deploy to container Plugin. 2.在构建任务中填加构建后操作.并做如下配置: WAR/EAR files:是war包的相对路径,如target/xxx.war c ...

  7. 关于在记事本写入"\n"不显示换行的原因

    Linux系统下直接使用  "\n"  即可换行 windows下需要使用   "\r\n"

  8. 剖析Unreal Engine超真实人类的渲染技术Part 3 - 毛发渲染及其它

    目录 四.毛发渲染 4.1 毛发的构造及渲染技术 4.1.1 毛发的构造 4.1.2 Marschner毛发渲染模型 4.1.3 毛发的间接光照 4.2 毛发的底层实现 4.3 毛发的材质解析 4.3 ...

  9. Java用Zip进行压缩

    这个总结源于Java编程思想第四版18.11节的案例: 完整代码地址: Java编程思想:压缩 相关Api地址: ZipStream ZipEntry ZipFile 进行压缩时: 1.创建Check ...

  10. Java开发实例大全:3月14日练习

    import java.io.FileNotFoundException; import java.io.PrintStream; import java.math.BigDecimal; impor ...