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. Oracle Awr报告_生成

    AWR的概念 Oracle数据库是一个使用量很多的数据库,关于Oracle数据库的性能.Oracle10g以后,Oracle提供了一个性能检测的工具:AWR(Automatic Workload Re ...

  2. Node.js实现PC端类微信聊天软件(五)

    Github StackChat 学习回顾 Socket.io 结合Express创建Socket.io服务器 const app = require('express')() const http ...

  3. php如何定义数组常量

    是这样吗?<?php define('BEST_PHPER',array('name'=>'巩文','address'=>'china')); My God,明确告诉你不可以:原因是 ...

  4. 如何让apache支持.htaccess 解决Internal Server Error The server …错误

    如何让apache支持.htaccess 解决Internal Server Error The server …错误 文章来源:小灰博客| 时间:2013-12-25 12:17:08| 作者:Le ...

  5. ZooKeeper入门(一)

    1 基本概念 1.1 什么是ZooKeeper zookeeper是为分布式应用所设计的高可用.高性能且一致的开源协调服务 1.2 Zookeeper的特点 顺序一致性 原子性 单一视图 可靠性 实时 ...

  6. intel FPGA CLKn pin 是否能直接进PLL?

    原创 by DeeZeng FPGA的时钟需要从专用的时钟管脚输入,那CLKn 作为Single-End时钟pin时是否能直接进 PLL呢? 通过查看对应FPGA型号的手册,得出以下结论 1. Cyc ...

  7. Java 将Word转为PDF、PNG、SVG、RTF、XPS、TXT、XML

    同一文档在不同的编译或阅读环境中,需要使用特定的文档格式来打开,通常需要通过转换文档格式的方式来实现.下面将介绍在Java程序中如何来转换Word文档为其他几种常见文档格式,如PDF.图片png.sv ...

  8. 使用Task实现非阻塞式的I/O操作

    在前面的<基于任务的异步编程模式(TAP)>文章中讲述了.net 4.5框架下的异步操作自我实现方式,实际上,在.net 4.5中部分类已实现了异步封装.如在.net 4.5中,Strea ...

  9. DRF + react 实现TodoList

    在web项目构建中有很多框架可供选择,开发人员对项目的使用选择,有很多的影响因素,其中之一就是框架在定义该项目的单独任务时的复杂性. 简介 本文有如下几个部分: 准备 配置后端 配置APIs 配置前端 ...

  10. 用Python玩数据-笔记整理-第二章-练习与测试

    课间练习:  经典问题的Python编程 按公式:C= 5/9×(F-32) ,将华氏温度转换成摄氏温度,并产生一张华氏0-300度与对应的摄氏温度之间的对照表(每隔20度输出一次) 验证命题:如果一 ...