C# HttpClient 突然停止下载

C# HttpClient Abruptly stops download

我有这个 C# 脚本,它应该从 GitHub 下载一个 zip 存档,解压它并将它放在一个特定的文件夹中:

using (var client = new HttpClient())
{
    var filePath = Path.GetFullPath("runtime");@"https://github.com/BlackBirdTV/tank/releases/latest/download/runtime.zip?raw=true";
    ConsoleUtilities.UpdateProgress("Downloading Runtime...", 0);
    var request = await client.GetStreamAsync(url);
    var buffer = new byte[(int)bufferSize];
    var totalBytesRead = 0;
    int bytes = 0;
    while ((bytes = await request.ReadAsync(buffer, 0, buffer.Length)) != 0)
    {
        totalBytesRead += bytes;
        ConsoleUtilities.UpdateProgress($"Downloading Runtime... ({totalBytesRead} of {bufferSize} bytes read) ", (int)(totalBytesRead / bufferSize * 100));
    }
}
Decompress(buffer, filePath);

当我现在运行这个时候,下载开始了,看起来好像已经完成了,但在一个零星的地方它只是停止了。不知何故,它下载了我的控制台显示的字节,但它们被清零了。似乎我的计算机接收到零(我对此表示怀疑)或者字节没有写入缓冲区。

奇怪的是,通过浏览器下载文件工作得很好。

非常感谢任何帮助

正如我在评论中所述,您的问题是 while 循环的每次迭代都会覆盖您的缓冲区,并且您没有在任何地方累积数据。所以你的最后一次迭代并没有完全填满缓冲区,你剩下的就是你在最后一次迭代中得到的任何数据。

您可以通过将累积的缓冲区存储在某处来修复该错误,但更好的解决方案是不要对缓冲区等大惊小怪,而只需使用 built-in CopyToAsync 方法 Stream:

using var client = new HttpClient();
using var stream = await client.GetStreamAsync("https://github.com/BlackBirdTV/tank/releases/latest/download/runtime.zip?raw=true");
using var file = new FileStream(@"c:\temp\runtime.zip", FileMode.Create);
await stream.CopyToAsync(file);

这里我将其保存到位于 c:\temp\runtime.zip 的本地文件中,但显然要根据您的需要进行更改。我想你是在避免使用这种方法,这样你就可以跟踪进度,这很公平。因此,如果这对您来说真的很重要,请继续阅读以修复您的原始解决方案。


为了完整起见,这是通过将缓冲区写入 FileStream:

修复的原始代码
var bufferSize = 1024 * 10;
var url = @"https://github.com/BlackBirdTV/tank/releases/latest/download/runtime.zip?raw=true";

using var client = new HttpClient();
using var stream = await client.GetStreamAsync(url);
using var file = new FileStream(@"c:\temp\runtime.zip", FileMode.Create);

var filePath = Path.GetFullPath("runtime"); 
var request = await client.GetStreamAsync(url);
var buffer = new byte[(int)bufferSize];
var totalBytesRead = 0;
int bytes = 0;
while ((bytes = await request.ReadAsync(buffer, 0, buffer.Length)) != 0)
{
    await file.WriteAsync(buffer, 0, bytes);
    totalBytesRead += bytes;
    ConsoleUtilities.UpdateProgress($"Downloading Runtime... ({totalBytesRead} of {bufferSize} bytes read) ", (int)(totalBytesRead / bufferSize * 100));
}