一种消耗(所有字节)BinaryReader 的优雅方式?
Posted
技术标签:
【中文标题】一种消耗(所有字节)BinaryReader 的优雅方式?【英文标题】:An elegant way to consume (all bytes of a) BinaryReader? 【发布时间】:2012-01-26 15:27:42 【问题描述】:用BinaryReader
模拟StreamReader.ReadToEnd
方法有什么优雅的吗?也许将所有字节放入一个字节数组中?
我这样做:
read1.ReadBytes((int)read1.BaseStream.Length);
...但必须有更好的方法。
【问题讨论】:
我认为毕竟这是一种优雅的赌注方式 【参考方案1】:遇到同样的问题。 首先,使用 FileInfo.Length 获取文件的大小。 接下来,创建一个字节数组并将其值设置为 BinaryReader.ReadBytes(FileInfo.Length)。 例如
var size = new FileInfo(yourImagePath).Length;
byte[] allBytes = yourReader.ReadBytes(System.Convert.ToInt32(size));
【讨论】:
【参考方案2】:我使用它,它利用底层的BaseStream
属性为您提供所需的长度信息。它使事情变得简单而美好。
下面是BinaryReader
上的三种扩展方法:
Range
类型来指定您感兴趣的数据子集。
public static class BinaryReaderExtensions
public static byte[] ReadBytesToEnd(this BinaryReader binaryReader)
var length = binaryReader.BaseStream.Length - binaryReader.BaseStream.Position;
return binaryReader.ReadBytes((int)length);
public static byte[] ReadAllBytes(this BinaryReader binaryReader)
binaryReader.BaseStream.Position = 0;
return binaryReader.ReadBytes((int)binaryReader.BaseStream.Length);
public static byte[] ReadBytes(this BinaryReader binaryReader, Range range)
var (offset, length) = range.GetOffsetAndLength((int)binaryReader.BaseStream.Length);
binaryReader.BaseStream.Position = offset;
return binaryReader.ReadBytes(length);
使用它们就变得简单明了...
// 1 - Reads everything in as a byte array
var rawBytes = myBinaryReader.ReadAllBytes();
// 2 - Reads a string, then reads the remaining data as a byte array
var someString = myBinaryReader.ReadString();
var rawBytes = myBinaryReader.ReadBytesToEnd();
// 3 - Uses a range to read the last 44 bytes
var rawBytes = myBinaryReader.ReadBytes(^44..);
【讨论】:
【参考方案3】:原始答案(阅读下面的更新!)
简单地做:
byte[] allData = read1.ReadBytes(int.MaxValue);
documentation 表示它将读取所有字节,直到到达流的末尾。
更新
虽然这看起来很优雅,并且文档似乎表明这会起作用,但实际的实现(在 .NET 2、3.5 和 4 中检查)为数据,这可能会在 32 位系统上导致 OutOfMemoryException
。
因此,我会说实际上没有优雅的方式。
相反,我会推荐@iano 答案的以下变体。此变体不依赖 .NET 4:
为BinaryReader
(或Stream
,代码相同)创建一个扩展方法。
public static byte[] ReadAllBytes(this BinaryReader reader)
const int bufferSize = 4096;
using (var ms = new MemoryStream())
byte[] buffer = new byte[bufferSize];
int count;
while ((count = reader.Read(buffer, 0, buffer.Length)) != 0)
ms.Write(buffer, 0, count);
return ms.ToArray();
【讨论】:
这给了我 .NET 4.0 中的 OutOfMemoryException(使用 LINQPad 进行测试)。实际上,使用 Reflector 对源代码进行反编译表明,ReadBytes 尝试分配一个具有给定计数大小的字节数组:byte[] buffer = new byte[count];. @iano 你是对的。我也反编译了.NET 2.0,也是一样。我将用免责声明更新我的答案。 有人可以向我解释为什么 buffer = new byte[count] 会导致内存不足异常吗?我想了解为什么需要缓冲的基本原理。谢谢 @ShrageSmilowitz 好吧,如果您创建一个包含int.MaxValue
32 位整数的数组,您将分配 8GB 内存……所以您应该使用更小的缓冲区来构建结果!
@user626528 早在 2011 年,当 .NET 3.5 占主导地位时,这是最简单的答案。我同意你的看法,现在 iano 的回答要好得多。【参考方案4】:
解决这个问题的另一种方法是使用 C# 扩展方法:
public static class StreamHelpers
public static byte[] ReadAllBytes(this BinaryReader reader)
// Pre .Net version 4.0
const int bufferSize = 4096;
using (var ms = new MemoryStream())
byte[] buffer = new byte[bufferSize];
int count;
while ((count = reader.Read(buffer, 0, buffer.Length)) != 0)
ms.Write(buffer, 0, count);
return ms.ToArray();
// .Net 4.0 or Newer
using (var ms = new MemoryStream())
stream.CopyTo(ms);
return ms.ToArray();
使用这种方法将允许可重用和可读的代码。
【讨论】:
这不会构建 - .NET 4.0 部分下的“流”变量未在任何地方定义。【参考方案5】:为了将一个流的内容复制到另一个,我已经解决了读取“一些”字节直到到达文件末尾的问题:
private const int READ_BUFFER_SIZE = 1024;
using (BinaryReader reader = new BinaryReader(responseStream))
using (BinaryWriter writer = new BinaryWriter(File.Open(localPath, FileMode.Create)))
int byteRead = 0;
do
byte[] buffer = reader.ReadBytes(READ_BUFFER_SIZE);
byteRead = buffer.Length;
writer.Write(buffer);
byteTransfered += byteRead;
while (byteRead == READ_BUFFER_SIZE);
【讨论】:
这对我有用,谢谢。 (您需要删除 'byteTransfered += byteRead;' 行才能按原样运行。)【参考方案6】:BinaryReader 没有一种简单的方法可以做到这一点。如果您不知道需要提前读取的计数,最好使用 MemoryStream:
public byte[] ReadAllBytes(Stream stream)
using (var ms = new MemoryStream())
stream.CopyTo(ms);
return ms.ToArray();
为避免在调用ToArray()
时产生额外的副本,您可以改为通过GetBuffer()
返回Position
和缓冲区。
【讨论】:
我同意,这可能是最优雅的答案。不过值得注意的是,Stream.CopyTo
仅在 .NET 4 中可用。
+1。在为我的困境寻找解决方案时,我偶然发现了这个答案。我在一个派生自Stream
的第3 方程序集中的类(我想从中获取所有字节)中遇到问题,但它的Length
属性始终为零。我最初尝试了一种基于扩展方法的方法,但觉得它很笨拙。
我会添加 stream.Position = 0;复制到之前
你如何获得流媒体?讨厌这些不完整的答案
@GustavoBaiocchiCosta yourBinaryReader.BaseStream
以上是关于一种消耗(所有字节)BinaryReader 的优雅方式?的主要内容,如果未能解决你的问题,请参考以下文章
原 BinaryWriter和BinaryReader(二进制文件的读写)