より良いエンジニアを目指して

1日1つ。良くなる!上手くなる!

コンソールアプリケーションで0%,1%,2%...と進捗状況を%表示するには

自社の QAエンジニアと共にインストール検証をしていた時のこと。

f:id:rimever:20190228201059p:plain

QAエンジニア「これ、すごくないですか。どうやって表示するんですかね?」

私「確かに」

彼が言っているのは%の部分です、進捗に応じて、コンソール上の%の値が書き換わっています。

「======50%   」

といったように。

C#のコンソール出力だとConsole.WriteLineやConsole.Writeなどで出力はできますし、PythonでもCでもprintメソッドがありますし、bashだってechoで出力できます。

しかし、一度出力した内容を書き直せるのか?

ということは考えたこともありませんし、やったこともありませんでした。

QAエンジニアであれば驚いて楽しんでもらえればいいですが、開発エンジニアの私としては驚いているだけでは立場が無いので試してみることにしました。

ConsoleのSetCursorPositionを使う方法

下記のStackOverflowを読んで知ったのですが、ConsoleクラスにはSetCursorPositionがあります。

stackoverflow.com

using System;
using System.Linq;
using System.Threading;

namespace ProgressConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("進捗を表示します。");
            var top = Console.CursorTop;
            var left = Console.CursorLeft;
            foreach (var value in Enumerable.Range(1,100))
            {
                Console.SetCursorPosition(left, top);
                Console.Write(value + "%");
                Thread.Sleep(100);
            }
            Console.WriteLine("完了");
        }
    }
}

こんな感じ。

f:id:rimever:20190228202731p:plain

ShellProgressBar

より高性能なのを求めるのであれば、ShellProgressBarというライブラリを使うと良さそうです。

f:id:rimever:20190228204120p:plain

考えた見せ方ですね。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ShellProgressBar;

namespace TryShellProgressBar
{
    class Program
    {
        static void Main(string[] args)
        {
            const int totalTicks = 100;
            var options = new ProgressBarOptions
            {
                ProgressCharacter = '─',
                ProgressBarOnBottom = true
            };
            using (var progressBar = new ProgressBar(totalTicks, "Initial message", options))
            {
                foreach (var percent in Enumerable.Range(1,totalTicks))
                {
                    Thread.Sleep(100);
                    progressBar.Tick($"{percent}%まで処理しています。");
                }
            }

            Console.ReadKey();
        }
    }
}