如何在 C# 控制台应用程序中正确写出下载状态?
How can I write out correctly the download status in C# console app?
我有以下代码,除了写出下载状态外,它工作正常。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void clear()
{
Thread.Sleep(1500);
Console.SetCursorPosition(0, 0);
}
static void Main(string[] args)
{
var client = new WebClient();
client.DownloadProgressChanged += (o, e) =>
{
Console.Write(e.ProgressPercentage + "% ");
clear();
};
client.DownloadFileAsync(new Uri("http://XXX"), "file");
Console.ReadKey();
}
}
}
使用代码将插入许多新行并且不会更新和打印下载状态。
在我的例子中,如果您也处理 DownloadFileCompleted 事件,它就可以工作。
client.DownloadFileCompleted += (e, s) =>
{
Console.WriteLine("Completed!");
};
你还应该使用 client.Dispose() 或将你的代码写在 使用语句:
using (WebClient client = new WebClient())
{
// Code which uses WebClient
}
这将自动释放资源。
编辑:
正如 rene 正确注意到的那样,在这种情况下没有必要使用 Dispose但通常最好记住 using 语句通常与 IDisposible 或 IO 操作一起使用。
您可以在每次更新前调用 Console.Clear()。这将从您的控制台中删除所有文本。这会将您的代码更改为:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void clear()
{
Thread.Sleep(1500);
Console.SetCursorPosition(0, 0);
}
static void Main(string[] args)
{
var client = new WebClient();
client.DownloadProgressChanged += (o, e) =>
{
Console.Clear();
Console.Write(e.ProgressPercentage + "% ");
clear();
};
client.DownloadFileAsync(new Uri("http://XXX"), "file");
Console.ReadKey();
}
}
}
为了什么 Thread.Sleep
?删除它。
如果你想保留控制台的内容,那么每次保存光标坐标并设置它。
using (var client = new WebClient())
{
int left = Console.CursorLeft;
int top = Console.CursorTop;
client.DownloadProgressChanged += (o, e) =>
{
Console.SetCursorPosition(left, top);
Console.Write(e.ProgressPercentage + "% ");
};
client.DownloadFileAsync(...);
Console.ReadKey();
}
DownloadProgressChanged
事件可以被多个线程同时调用,所以你需要注意它,例如使用 lock
如下所示。
也不要在事件处理程序中使用 Thread.Sleep()
!这绝不是个好主意。在这种特殊情况下,当线程处于休眠状态时,下载无法继续,导致下载速度明显变慢。如果您想限制屏幕更新的频率(以降低 CPU 负载并避免屏幕闪烁),只需跳过在上一个事件之后发生得太快的事件。
static void Main(string[] args)
{
var client = new WebClient();
Object LockObject = new Object();
DateTime LastProgressUpdateTime = DateTime.MinValue;
long LastProgressUpdatePosition = -1;
TimeSpan DesiredProgressUpdatePeriod = TimeSpan.FromMilliseconds(1500);
client.DownloadProgressChanged += (o, e) =>
{
//Prevent multipe concurrent thread to update progress at once
lock (LockObject)
{
// This prevents updating progress to value that is lower than
// what we already printed. This could happen when threads
// enters lock out of order.
if (LastProgressUpdatePosition > e.BytesReceived)
return;
// This is not neccessary, but prevents you to miss 100% progress event ()
var isCompleted = e.TotalBytesToReceive != 0 && e.BytesReceived == e.TotalBytesToReceive;
// Check if desired time elapsed since last update
bool UpdatePeriodElapsed = DateTime.Now >= LastProgressUpdateTime + DesiredProgressUpdatePeriod;
if(isCompleted || UpdatePeriodElapsed)
{
Console.SetCursorPosition(0, 0);
Console.Write(e.ProgressPercentage + "%");
LastProgressUpdatePosition = e.BytesReceived;
LastProgressUpdateTime = DateTime.Now;
}
}
};
client.DownloadFileAsync(new Uri("..."), "...");
Console.ReadKey();
}
我有以下代码,除了写出下载状态外,它工作正常。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void clear()
{
Thread.Sleep(1500);
Console.SetCursorPosition(0, 0);
}
static void Main(string[] args)
{
var client = new WebClient();
client.DownloadProgressChanged += (o, e) =>
{
Console.Write(e.ProgressPercentage + "% ");
clear();
};
client.DownloadFileAsync(new Uri("http://XXX"), "file");
Console.ReadKey();
}
}
}
使用代码将插入许多新行并且不会更新和打印下载状态。
在我的例子中,如果您也处理 DownloadFileCompleted 事件,它就可以工作。
client.DownloadFileCompleted += (e, s) =>
{
Console.WriteLine("Completed!");
};
你还应该使用 client.Dispose() 或将你的代码写在 使用语句:
using (WebClient client = new WebClient())
{
// Code which uses WebClient
}
这将自动释放资源。
编辑:
正如 rene 正确注意到的那样,在这种情况下没有必要使用 Dispose但通常最好记住 using 语句通常与 IDisposible 或 IO 操作一起使用。
您可以在每次更新前调用 Console.Clear()。这将从您的控制台中删除所有文本。这会将您的代码更改为:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void clear()
{
Thread.Sleep(1500);
Console.SetCursorPosition(0, 0);
}
static void Main(string[] args)
{
var client = new WebClient();
client.DownloadProgressChanged += (o, e) =>
{
Console.Clear();
Console.Write(e.ProgressPercentage + "% ");
clear();
};
client.DownloadFileAsync(new Uri("http://XXX"), "file");
Console.ReadKey();
}
}
}
为了什么 Thread.Sleep
?删除它。
如果你想保留控制台的内容,那么每次保存光标坐标并设置它。
using (var client = new WebClient())
{
int left = Console.CursorLeft;
int top = Console.CursorTop;
client.DownloadProgressChanged += (o, e) =>
{
Console.SetCursorPosition(left, top);
Console.Write(e.ProgressPercentage + "% ");
};
client.DownloadFileAsync(...);
Console.ReadKey();
}
DownloadProgressChanged
事件可以被多个线程同时调用,所以你需要注意它,例如使用 lock
如下所示。
也不要在事件处理程序中使用 Thread.Sleep()
!这绝不是个好主意。在这种特殊情况下,当线程处于休眠状态时,下载无法继续,导致下载速度明显变慢。如果您想限制屏幕更新的频率(以降低 CPU 负载并避免屏幕闪烁),只需跳过在上一个事件之后发生得太快的事件。
static void Main(string[] args)
{
var client = new WebClient();
Object LockObject = new Object();
DateTime LastProgressUpdateTime = DateTime.MinValue;
long LastProgressUpdatePosition = -1;
TimeSpan DesiredProgressUpdatePeriod = TimeSpan.FromMilliseconds(1500);
client.DownloadProgressChanged += (o, e) =>
{
//Prevent multipe concurrent thread to update progress at once
lock (LockObject)
{
// This prevents updating progress to value that is lower than
// what we already printed. This could happen when threads
// enters lock out of order.
if (LastProgressUpdatePosition > e.BytesReceived)
return;
// This is not neccessary, but prevents you to miss 100% progress event ()
var isCompleted = e.TotalBytesToReceive != 0 && e.BytesReceived == e.TotalBytesToReceive;
// Check if desired time elapsed since last update
bool UpdatePeriodElapsed = DateTime.Now >= LastProgressUpdateTime + DesiredProgressUpdatePeriod;
if(isCompleted || UpdatePeriodElapsed)
{
Console.SetCursorPosition(0, 0);
Console.Write(e.ProgressPercentage + "%");
LastProgressUpdatePosition = e.BytesReceived;
LastProgressUpdateTime = DateTime.Now;
}
}
};
client.DownloadFileAsync(new Uri("..."), "...");
Console.ReadKey();
}