在异步代码中使用BinaryWriter或BinaryReader

Yus*_*dın 5 c# binaryreader binarywriter async-await

我有一个float写入文件的列表.下面的代码做了事情,但它是同步的.

List<float> samples = GetSamples();

using (FileStream stream = File.OpenWrite("somefile.bin"))
using (BinaryWriter binaryWriter = new BinaryWriter(stream, Encoding.Default, true))
{
    foreach (var sample in samples)
    {
        binaryWriter.Write(sample);
    }
}
Run Code Online (Sandbox Code Playgroud)

我想异步操作但BinaryWriter不支持异步操作,这是正常的,因为它每次只写几个字节.但大多数情况下,操作使用文件I/O,我认为它可以而且应该是异步的.

我试着写一个MemoryStreamBinaryWriter和时完成我复制MemoryStreamFileStreamCopyToAsync,然而这引起性能下降(总时间)高达100%的大文件.

如何将整个操作转换为异步?

Ben*_*igt 5

正常的写操作通常最终还是以异步方式完成。操作系统立即接受写入写缓存的写入,并在以后将其刷新到磁盘。您的应用程序不受实际磁盘写操作的阻止。

当然,如果要写入可移动驱动器,则通常会禁用写缓存,并且程序将被阻止。


我建议您通过一次传送一个大块来大大减少操作次数。以机智:

  1. 分配new T[BlockSize]您所需的块大小。
  2. 分配一个 new byte[BlockSize * sizeof (T)]
  3. 用于List<T>.CopyTo(index, buffer, 0, buffer.Length)从列表中复制批次。
  4. 用于Buffer.BlockCopy将数据导入byte[]
  5. byte[]只需一次操作即可将写入流中。
  6. 重复3-5,直到到达列表末尾。小心最后一批,这可能是一部分。


Lua*_*aan 1

您的内存流方法是有意义的,只需确保批量写入,而不是等待内存流增长到文件的完整大小,然后一次全部写入。

像这样的东西应该可以正常工作:

var data = new float[10 * 1024];
var helperBuffer = new byte[4096];

using (var fs = File.Create(@"D:\Temp.bin"))
using (var ms = new MemoryStream(4096))
using (var bw = new BinaryWriter(ms))
{
  var iteration = 0;

  foreach (var sample in data)
  {
    bw.Write(sample);

    iteration++;

    if (iteration == 1024)
    {
      iteration = 0;
      ms.Position = 0;

      ms.Read(helperBuffer, 0, 1024 * 4);
      await fs.WriteAsync(helperBuffer, 0, 1024 * 4).ConfigureAwait(false);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这只是示例代码 - 确保正确处理错误等。