Skip to content

Instantly share code, notes, and snippets.

@kice
Last active July 15, 2021 10:29
Show Gist options
  • Save kice/075f08092738729651b2851191dc220d to your computer and use it in GitHub Desktop.
Save kice/075f08092738729651b2851191dc220d to your computer and use it in GitHub Desktop.
using System;
using System.Runtime.InteropServices;
namespace CSProgressBar
{
public class ProgressBar
{
private readonly int maxLength;
private int lastLen;
private double total;
private double current;
private readonly long freq = TimeSpan.TicksPerSecond;
private long start;
private long last;
private double updated;
private readonly object _lock = new object();
private double average = -1; // average speed
private static char[] bars = { ' ', '▏', '▎', '▍', '▌', '▋', '▊', '▉', '█' };
public ProgressBar(double total, int maxLength = 0)
{
this.total = total;
this.maxLength = maxLength < 1 ? Console.BufferWidth / 2 : maxLength;
this.maxLength = maxLength < 1 ? 60 : this.maxLength;
start = DateTime.Now.Ticks;
}
public void WriteLine(string text)
{
if (text.Length < lastLen)
{
Console.WriteLine(text + string.Empty.PadRight(lastLen - text.Length, ' '));
}
else
{
Console.WriteLine(text);
}
}
public void Update(double count = 1, string prefix = null, string postfix = null)
{
lock(_lock) {
current += count;
current = current >= total ? total : current;
long now = DateTime.Now.Ticks;
int elapsed = (int)((now - start) / freq);
float delta = (float)(now - last) / freq;
updated += count;
if (delta > 0.1f)
{
double speed = updated / delta;
speed = double.IsNaN(speed) || double.IsInfinity(speed) ? 0 : speed;
last = now;
updated = 0;
// running average, update per second
average = average < 0 ? speed : average + 0.2f * (speed - average);
}
int eta = (int)Math.Round((total - current) / (average < 0 ? count : average)); // in second
int length = 4;
string status = $"{elapsed / 60:D2}:{elapsed % 60:D2}<{eta / 60:D2}:{eta % 60:D2}, {average:F2}it/s";
length += status.Length;
double percent = current / total;
int msglen = string.IsNullOrEmpty(prefix) ? 0 : prefix.Length;
msglen += string.IsNullOrEmpty(postfix) ? 0 : postfix.Length;
int maxlen = maxLength - msglen;
if (maxlen <= 0)
{
maxlen = maxLength;
prefix = null;
postfix = null;
}
double l = percent * (maxLength - length);
int len = (int)l;
string bar = string.Empty.PadLeft(len, bars[8]);
if (current != total)
{
bar += bars[(int)((l - len) * 8)];
bar += string.Empty.PadRight(maxLength - length - len, ' ');
}
string output = $"{(percent * 100f).ToString("0").PadLeft(3, ' ')}%|{bar}| {current:F0}/{total:F0} [{status}]{(current == total ? "\n" : "\r")}";
if (!string.IsNullOrEmpty(prefix))
{
output = prefix + output;
}
if (!string.IsNullOrEmpty(postfix))
{
output += postfix;
}
if (current == total)
{
output += '\n';
}
Console.Write(string.Empty.PadRight(lastLen, '\b') + output);
lastLen = output.Length;
}
}
}
internal class Program
{
private static void Main(string[] args)
{
var progress = new ProgressBar(1000);
for (int i = 0; i < 1000; i += 10)
{
progress.Update(10);
System.Threading.Thread.Sleep(100);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment