【问题标题】:Download a file with HttpClient but defer writing使用 HttpClient 下载文件但延迟写入
【发布时间】:2020-01-27 17:22:11
【问题描述】:

我可以下载 byte[]'s 并将它们写入文件没有问题,much link this link does。但是,当我进行简单的更改,将 bytes[] 和 readCount 保存到一个列表中,然后在列表上进行 foreach 时,我得到了一个损坏的文件。

下面是部分代码,说明了我的意思。有两个注释路径:一个存储字节/计数(和顺序),然​​后在读取完成时写入。另一个写入与每次读取一致。

由于 order 字段,我已经验证了 foreach 正在以正确的顺序写入字节,但部分代码清单没有明确使用它。

    private class ByteHolder
    {
        public byte[] Buffer { get; set; } = new byte[8192];
        public int BytesRead { get; set; }
        public int Order { get; set; }
    }

    var byteList = new List<ByteHolder>();

    using (var fileStream = new FileStream(_fileBytes.SavingPath.RuntimePath(), FileMode.Create, FileAccess.Write, FileShare.None, 8192, true))
    {
        do
        {
            var bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length);
            if (bytesRead == 0)
            {

                //--- WRITING THE bytes and counts this way produces corrupt file -->
                var offset = 0;
                foreach (var byteHolder in byteList)
                {
                    await fileStream.WriteAsync(byteHolder.Buffer, offset, byteHolder.BytesRead).ConfigureAwait(false);
                    offset += 8192;
                }

                isMoreToRead = false;
                FileDownloadComplete?.Invoke(this, _fileBytes);
                continue;
            }

            //--- Storing them in this class and list for writing above DOES NOT WORK -->
            byteList.Add(new ByteHolder() { Buffer = buffer, BytesRead = bytesRead, Order = readCount }); 

            //--- Writing inline with the read WORKS -->
            //await fileStream.WriteAsync(buffer, 0, bytesRead);

            readCount++;
            totalBytesRead += bytesRead;

【问题讨论】:

  • 所以你总是将数据从偏移量 0 写入文件,你需要在“foreach”循环中增加偏移量。
  • 感谢您的回复。我在上面的示例代码中添加了偏移量。它仍然会生成损坏的文件。不确定我是否应该抵消缓冲区大小或读取大小,但两者都不起作用。我正在使用的文件是 xlsx。 (此外,内联 WriteAsync 使用偏移量 0 并且它有效!?)特定的 xlsx 需要四次读取才能下载。
  • 看一下WriteAsync的文档,你传入的偏移量是buffer中的偏移量,而不是文件中的偏移量。它应该始终为 0;增量是不必要的。
  • buffer 在哪里初始化?在这里,您在每个循环上重用相同的缓冲区数组,这就是导致问题的原因。每次阅读都必须创建一个新的缓冲区数组。
  • Mike Zboray,“每次阅读时创建一个新缓冲区”就是答案。非常感谢!这不是一个非常明显的解决方案。

标签: c# .net-core download httpclient


【解决方案1】:
            foreach (var byteHolder in byteList)
            {
                var offset = 0;
                await fileStream.WriteAsync(byteHolder.Buffer, offset, byteHolder.BytesRead).ConfigureAwait(false);
                offset += 8192;
            }

无论您当时正在处理哪个byteHolder 实例,您总是在偏移量0 处写入。

【讨论】:

  • 无论如何,你的整个算法都是错误的,在将它写入磁盘之前,你不应该将整个东西保存在内存中,只要将你得到的部分写下来。
  • 我已经尝试过各种方式。布林迪注意到了一个问题。我修好了它。同样的问题。我不能按照你的建议做,因为最终这个文件将通过无法处理字节的 SignalR 传输。在您对此表示犯规之前,我已经验证了我可以通过 SignalR 传输 Base64 表示而不会出错。无论如何,问题发生在 SignalR 之前。
  • 无论传输的是什么,您都在使用称为套接字的操作系统结构。您认为“无法处理字节”是什么意思并不重要,(tcp)套接字以您请求的大小的块将字节流式传输给您。
  • 我希望这是真的。它会为我节省几天的时间。然而,当我 SendAsync 一个 List 时,它永远不会触发 .On。我改变那个调用来发送一个字符串并且 .On 触发。
猜你喜欢
  • 2016-05-20
  • 2020-10-31
  • 2015-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-14
  • 2019-12-20
  • 2020-03-25
相关资源
最近更新 更多