diff --git a/src/EasilyNET.Core/Misc/TextWriterExtensions.cs b/src/EasilyNET.Core/Misc/TextWriterExtensions.cs new file mode 100644 index 00000000..31880a12 --- /dev/null +++ b/src/EasilyNET.Core/Misc/TextWriterExtensions.cs @@ -0,0 +1,117 @@ +using EasilyNET.Core.Threading; + +// ReSharper disable UnusedMember.Global +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable UnusedType.Global + +namespace EasilyNET.Core.Misc; + +/// +/// 扩展方法 +/// +public static class TextWriterExtensions +{ + private static readonly AsyncLock _lock = new(); + + /// + /// 线程安全的控制台在同一行输出消息 + /// + /// + /// 使用方式: + /// + /// + /// + /// + /// + /// + /// + /// + public static async Task SafeWriteOutput(this TextWriter writer, string msg) + { + using (await _lock.LockAsync()) + { + ClearCurrentLine(); + await writer.WriteAsync(msg); + } + } + + /// + /// 线程安全的清除当前行 + /// + /// + /// 使用方式: + /// + /// + /// + /// + /// + /// + /// + public static async Task SafeClearCurrentLine(this TextWriter _) + { + using (await _lock.LockAsync()) + { + ClearCurrentLine(); + } + } + + private static void ClearCurrentLine() + { + Console.SetCursorPosition(0, Console.CursorTop); + Console.Write(new string(' ', Console.WindowWidth)); + Console.SetCursorPosition(0, Console.CursorTop); + } + + /// + /// 在控制台输出进度条,用于某些时候需要显示进度的场景 + /// + /// Writer + /// 进度 + /// 消息 + /// 进度条整体宽度,包含消息部分 + /// 完成部分填充字符 + /// 未完成部分填充字符 + /// + /// + /// 使用方式: + /// + /// + /// + /// + /// + /// + public static async Task ShowProgressBar(this TextWriter writer, double progressPercentage, string message = "", int totalWidth = -1, char completedChar = '=', char incompleteChar = '-') + { + if (progressPercentage < 0) progressPercentage = 0; + if (progressPercentage > 100) progressPercentage = 100; + var progressText = $"{progressPercentage / 100.0:P1}"; + var extraWidth = progressText.Length + message.Length + 5; // 计算额外字符的宽度,包括边界和百分比信息 + try + { + // 确保 totalWidth 不为负数 + totalWidth = totalWidth == -1 ? Math.Max(0, Console.WindowWidth - extraWidth) : Math.Max(0, totalWidth - extraWidth); + } + catch (Exception) + { + // 如果 Console.WindowWidth 抛出异常说明当前环境不支持,则将 totalWidth 设置为 80 + totalWidth = Math.Max(0, 80 - extraWidth); + } + var progressBarWidth = (int)progressPercentage * totalWidth / 100; + if (Math.Abs(progressPercentage - 100) < 0.000001) progressBarWidth = totalWidth; // 确保在100%时填满进度条 + var progressBar = new string(completedChar, progressBarWidth).PadRight(totalWidth, incompleteChar); + var output = $"[{progressBar}] {progressText} {message}"; + await writer.SafeWriteOutput(output); + } +} \ No newline at end of file