我需要将IEnumerable<byte>
的字节写入文件
我可以将它转换为数组并使用Write(byte[])
方法:
using (var stream = File.Create(path))
stream.Write(bytes.ToArray());
但由于IEnumerable
未提供收藏品的项目数,因此不建议使用ToArray
{。{3}}。
所以我可以在每次迭代中迭代IEnumerable
并使用WriteByte(byte)
:
using (var stream = File.Create(path))
foreach (var b in bytes)
stream.WriteByte(b);
我想知道在写大量数据时哪一个会更快。
我想使用Write(byte[])
根据数组大小设置缓冲区,因此在数组方面会更快。
我的问题是,当我只有IEnumerable<byte>
有MB数据时,哪种方法更好?将它转换为数组并调用Write(byte[])
或迭代它并为每个数组调用WriteByte(byte)
?
答案 0 :(得分:3)
对大量字节流进行枚举是一个过程,会给通常很便宜的东西增加大量开销:将字节从一个缓冲区复制到下一个缓冲区。
通常情况下,LINQ样式的开销并不重要,但是当在普通硬盘驱动器上处理每秒1亿字节时,将注意到严重的开销。这是不过早优化。我们可以预见这将是一个性能热点,所以我们应该热切地优化。
因此,在复制字节时,您可能根本不应该依赖IEnumerable
和IList
之类的抽象。绕过也包含ArraySegement<byte>
和Offset
的数组或Count
。这使您免于经常切片数组。
高吞吐量IO的一个原因就是每个字节调用一个方法。就像逐字节读和逐字节写一样。此会杀死性能,因为这些方法必须每秒调用数亿次。我亲身经历过。
始终一次处理至少4096字节的整个缓冲区。根据您正在使用哪种媒体进行IO,您可以使用更大的缓冲区(64k,256k甚至兆字节)。
答案 1 :(得分:1)
您应该分析哪个版本更快。 FileStream
类有一个内部缓冲区,可以将Read()
和Write()
方法与实际文件系统访问分开。
如果未在FileStream
构造函数中指定缓冲区大小,则默认情况下它使用4096字节的缓冲区。该缓冲区将许多WriteByte()
调用合并到一个写入底层文件中。唯一的问题是WriteByte()
调用的开销是否会超过Enumerable.ToArray()
调用的开销。后者肯定会使用更多的内存,但你总是需要处理这种权衡。
仅供参考:Enumerable.ToArray()
的当前.NET 4实现涉及通过在必要时复制其大小来增长数组。每次增长时,都会复制所有值。此外,当所有项目都存储在数组中时,其内容将再次复制到最终大小的数组。对于实际实现IEnumerable<T>
的{{1}}个实例,代码利用这个事实从正确的数组大小开始,然后让集合进行复制。