3

我正在接收一个文件作为字节 [] 数据包流(预先不知道总大小),我需要将其存储在某个地方,然后在收到它后立即处理它(我不能即时进行处理)。接收到的文件总大小可以从小到 10 KB 到超过 4 GB 不等。

  • 存储接收到的数据的一个选项是使用一个MemoryStream,即一系列MemoryStream.Write(bufferReceived, 0, count)调用来存储接收到的数据包。这很简单,但显然会导致大文件出现内存不足异常。
  • 另一种选择是使用 a FileStream,即FileStream.Write(bufferReceived, 0, count)。这样,不会发生内存不足异常,但我不确定是由于磁盘写入导致的性能不佳(只要仍有足够的内存可用,我不希望发生这种情况) - 我想尽可能避免磁盘访问,但我不知道如何控制它。

MemoryStream.Write()我做了一些测试,在大多数情况下,说 10 000 次连续调用vs之间似乎几乎没有性能差异FileStream.Write(),但很大程度上取决于缓冲区大小和有问题的数据总量(即写入次数) . 显然,MemoryStream尺寸重新分配也是一个因素。

  1. MemoryStream使用and的组合是否有意义FileStream,即默认写入内存流,但是一旦接收到的数据总量超过例如 500 MB,将其写入FileStream;然后,从两个流中读取块以处理接收到的数据(首先从 500 MBMemoryStream处理,处理它,然后从 读取FileStream)?

  2. 另一种解决方案是使用自定义的内存流实现,它不需要连续的地址空间来进行内部数组分配(即内存流的链表);这样,至少在 64 位环境中,内存不足异常应该不再是问题。缺点:额外的工作,更多的错误空间。

那么FileStreamvsMemoryStream读/写在磁盘访问和内存缓存方面如何表现,即数据大小/性能平衡。我希望只要有足够的 RAM 可用,FileStream无论如何都会在内部从内存(缓存)读取/写入,而虚拟内存将负责其余的工作。FileStream但是我不知道在写入磁盘时会多久显式访问一次。

任何帮助,将不胜感激。

4

3 回答 3

5

不,尝试优化它没有任何意义。Windows 本身已经缓存了文件写入,它们由文件系统缓存缓冲。因此,您的测试是准确的, MemoryStream.Write() 和 FileStream.Write() 实际上都写入 RAM 并且没有显着的性能差异。文件系统驱动程序在后台将其延迟写入磁盘。

用于文件系统缓存的 RAM 是在进程声明其 RAM 需求后剩下的。通过使用 MemoryStream,您会降低文件系统缓存的有效性。或者换句话说,你用一个换另一个没有好处。事实上,你的情况更糟,你使用了两倍的 RAM。

不要帮忙,这已经在操作系统内部进行了高度优化。

于 2013-10-30T16:50:20.287 回答
3

由于最新版本的 Windows 默认启用写入缓存,我想说您可以简单地使用FileStream并让 Windows 管理何时或是否有任何内容实际写入物理硬盘驱动器。

如果这些文件在您收到后没有保留,您可能应该将文件写入临时目录并在完成后将其删除。

于 2013-10-30T15:51:22.877 回答
3

使用允许您定义缓冲区大小的FileStream 构造函数。例如:

using (outputFile = new FileStream("filename", 
    FileMode.Create, FileAccess.Write, FileShare.None, 65536))
{
}

默认缓冲区大小为 4K。使用 64K 缓冲区可减少对文件系统的调用次数。更大的缓冲区会减少写入次数,但每次写入开始需要更长的时间。经验数据(多年使用这些东西)表明 64K 是一个非常好的选择。

正如其他人指出的那样,文件系统可能会进行进一步的缓存,并在后台进行实际的磁盘写入。您接收数据的速度极不可能比将其写入FileStream.

于 2013-10-30T16:39:15.867 回答