一种消耗(一个字节的所有字节)BinaryReader的优雅方法?


67

有没有一种优雅的StreamReader.ReadToEnd方法可以模仿BinaryReader?也许将所有字节放入字节数组中?

我这样做:

read1.ReadBytes((int)read1.BaseStream.Length);

...但是必须有更好的方法。


2
我认为这毕竟是一种优雅的下注方式
卢卡

Answers:


98

原始答案(请阅读下面的更新!)

只需做:

byte[] allData = read1.ReadBytes(int.MaxValue);

文档说它将读取所有字节,直到到达流的末尾。


更新资料

尽管这看起来很优雅,并且文档似乎表明这可以工作,但实际的实现(在.NET 2、3.5和4中进行了检查)为数据分配了一个全尺寸的字节数组,这可能会导致OutOfMemoryException32位系统。

因此,我要说实际上并没有一种优雅的方法

相反,我建议使用@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();
    }
    
}

12
这给了我.NET 4.0中的OutOfMemoryException(使用LINQPad进行测试)。确实,使用Reflector对源进行反编译显示,ReadBytes尝试分配具有给定count大小的字节数组:byte [] buffer = new byte [count];。
iano

1
@iano你是正确的。我还对.NET 2.0进行了反编译,它是相同的。我将使用免责声明来更新我的答案。
Scott Rippey 2012年

有人可以向我解释一下为什么buffer = new byte [count]会导致内存不足异常的基本知识吗?我想了解缓冲为什么需要缓冲的基础。谢谢
Shrage Smilowi​​tz 2014年

1
@ShrageSmilowi​​tz好吧,如果您创建一个包含int.MaxValue32位整数的数组,则将分配8GB的内存...因此,这就是为什么您应该使用较小的缓冲区构建结果的原因!
Scott Rippey 2014年

1
@ user626528早在2011年,当.NET 3.5占主导地位时,这是最简单的答案。我同意你的看法,如今iano的答案要好得多。
Scott Rippey

75

使用BinaryReader没有简单的方法。如果您不知道需要提前读取的计数,那么更好的选择是使用MemoryStream:

public byte[] ReadAllBytes(Stream stream)
{
    using (var ms = new MemoryStream())
    {
        stream.CopyTo(ms);
        return ms.ToArray();
    }
}

为了避免在调用时产生额外的副本ToArray(),您可以改为通过Position和返回and缓冲区GetBuffer()


我同意,这可能是最优雅的答案。值得注意的是,虽然Stream.CopyTo只提供.NET 4
斯科特Rippey

+1。在寻找解决方案时,我偶然发现了这个答案。我在第3方程序集中的一个类上遇到了一个问题(我想从中获取所有字节),Stream但该类的Length属性始终为零。最初,我尝试了基于扩展方法的方法,但是感觉很麻烦。
Wai Ha Lee

2
我将添加stream.Position = 0; 在CopyTo之前
Ivan Sokalskiy

你怎么流?讨厌这些不完整的答案
Gustavo Baiocchi Costa

2
@GustavoBaiocchiCostayourBinaryReader.BaseStream
18

3

要将流的内容复制到另一个,我解决了读取“一些”字节直到到达文件末尾的问题:

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);                        
    }                
}

0

解决此问题的另一种方法是使用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();
      }
   }
}

使用这种方法将允许可重用​​和可读的代码。


6
这不会建立-在任何地方都未定义.NET 4.0节下的“ stream”变量。
BJ Myers 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.