Last active
July 15, 2021 10:29
-
-
Save kice/075f08092738729651b2851191dc220d to your computer and use it in GitHub Desktop.
A C# version of https://github.com/tqdm/tqdm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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