c# 控制台console进度条

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 = 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

时间: 2024-11-10 15:42:38

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

控制台进度条

今天在整理资料的时候,翻出多年前在网上看到的一篇帖子,一个控制台的进度条,非常酷炫,原文出处-传送门. 记得在刚开始接触编程的时候,用控制台写些小工具玩,也喜欢将信息打印到屏幕上,看着不断闪动的屏幕觉得很酷,后来一次偶然的机会看到了这个进度条让控制台的输出又上了一个层次,感谢作者. static void Main(string[] args) { Random r = new Random(); while (true) { ConsoleProgressBar bar = new Conso

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

看到[vb.net]控制台进度条的示例 感觉很好玩,翻译成C#版. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; namespace ConsoleProcessBar { class Program { static void Main(string[] args

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

with用法 with用法在python中是一个很独特的用法,因为别的语言的中没有这个用法.所以针对这个特点我们来做一次总结,什么样的情况下可以同with  我们学到的有文件的操作,和acquire   release 说道with首先要引入一个概念:上下文管理协议,支持该协议的对象内部要实现__enter__ ()          __exit__()  这两种方法 只要实现了这两种方法的对象,在做打开和关闭的操作时我们就可以直接用with来操作.详细请参考https://www.ibm.c

也说文件上传之兼容IE789的进度条---丢掉flash

最近在整理前端常用到的一些组件,像分页(get/post两类).下拉框(下拉单选/下拉多选/省市区联动).模态框等:当然还有文件上传啦,如果只考虑用HTML5的话,前端方面的工作,那家伙老简单了,分分钟搞定,不就是验证,显示文件信息,加个进度条,回调下么:好吧,说得简单而已,自己动手完整的实现一遍试试:对于PC端的前端而言,大多时候可能还得顾及一下IE7+:那么问题就来了,IE789都不支持H5的file API,so,让我们一起BSIE吧! 上传显示文件类型.大小.文件名,这些百度立马出结果,

Ajax上传文件进度条显示

要实现进度条的显示,就要知道两个参数,上传的大小和总文件的大小 html5提供了一个上传过程事件,在上传过程中不断触发,然后用已上传的大 小/总大小,计算上传的百分比,然后用这个百分比控制div框的显示,就可以 实现上传的进度条效果 前端页面 <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Ajax上传文件进度条显示

基于HT for Web矢量实现HTML5文件上传进度条

在HTML中,在文件上传的过程中,很多情况都是没有任何的提示,这在体验上很不好,用户都不知道到时有没有在上传.上传成功了没有,所以今天给大家介绍的内容是通过HT for Web矢量来实现HTML5文件上传进度条,矢量在<矢量Chart图表嵌入HTML5网络拓扑图的应用>一文中已经讲述了关于setCompType()方法的应用,今天我们用setImage()方法充分利用系统中定义好的矢量资源来实现文件上传进度条,我们先来看下效果图: 从效果图可以看到,向服务器上传了一个mp4文件,并在最下方显示

OpenCV GUI基本操作,回调函数,进度条,裁剪图像等

代码为转载,出处找不到了,不贴了 工具条进度条: // ConvertColor.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #pragma comment(lib,"opencv_core2410d.l

进度条的多种写法

1. animation; <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <style> #box { width: 600px; height: 30px; background-color: #ccc; } #move { width: 100%; height: 100%; background-color: #f00;

AJAX大文件切割上传以及带进度条。

分块传输的原理就是利用HTML5新增的文件slice截取函数. 代码如下: html: <input id="f" type="file" name="part" onchange="writeFile()"> JS: 核心部分已经加粗显示了,其他部分不用看,因为实现的方式有很多种,不一定要按照我的方式去写,但是核心是不会变的. var writeFile = function(){ var temp = null