C# 使用二进制读取器(所有字节)的优雅方式?

C# 使用二进制读取器(所有字节)的优雅方式?,c#,.net,stream,streamreader,binaryreader,C#,.net,Stream,Streamreader,Binaryreader,是否有一个优雅的方法来模拟StreamReader.ReadToEnd方法与BinaryReader?也许要将所有字节放入字节数组 我这样做: read1.ReadBytes((int)read1.BaseStream.Length); …但必须有更好的方法。原始答案(请阅读下面的更新!) 简单地做: byte[] allData = read1.ReadBytes(int.MaxValue); 表示它将读取所有字节,直到到达流的末尾 更新 尽管这看起来很优雅,而且文档似乎表明这会起作用,

是否有一个优雅的方法来模拟
StreamReader.ReadToEnd
方法与
BinaryReader
?也许要将所有字节放入字节数组

我这样做:

read1.ReadBytes((int)read1.BaseStream.Length);
…但必须有更好的方法。

原始答案(请阅读下面的更新!) 简单地做:

byte[] allData = read1.ReadBytes(int.MaxValue);
表示它将读取所有字节,直到到达流的末尾


更新 尽管这看起来很优雅,而且文档似乎表明这会起作用,但实际的实现(在.NET 2、3.5和4中签入)为数据分配了一个全尺寸字节数组,这可能会在32位系统上导致
OutOfMemoryException

因此,我想说实际上没有一种优雅的方式

相反,我会推荐@iano的答案的以下变体。此变体不依赖.NET 4:
BinaryReader
(或
Stream
,两者的代码都相同)创建扩展方法


使用BinaryReader没有一种简单的方法。如果您不知道需要提前阅读的计数,最好使用MemoryStream:

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

为了避免调用
ToArray()
时出现额外的复制,您可以通过
GetBuffer()

返回
位置和缓冲区,将流的内容复制到另一个,我解决了在到达文件结尾之前读取“某些”字节的问题:

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

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

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

我使用这种方法,它利用底层的
BaseStream
属性为您提供所需的长度信息。它使事情变得美好和简单

下面是
BinaryReader
上的三种扩展方法:

  • 第一个从流的当前位置到末尾的任何位置读取
  • 第二种方法一次读取整个流
  • 第三种方法利用
    范围
    类型指定您感兴趣的数据子集
使用它们是琐碎和清晰的

// 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..);


有同样的问题。
首先,使用FileInfo.Length获取文件大小。
接下来,创建一个字节数组并将其值设置为BinaryReader.ReadBytes(FileInfo.Length)。 e、 g


这给了我一个.NET4.0中的OutOfMemoryException(使用LINQPad测试)。实际上,使用Reflector反编译源代码会发现ReadBytes试图分配一个大小为给定计数的字节数组:byte[]buffer=new byte[count]@我不知道你是对的。我还反编译了.NET2.0,也是一样的。我要用一个免责声明更新我的答案。有人能给我解释一下buffer=new byte[count]会导致outofmemory异常的基本原因吗?我想了解为什么需要缓冲的基本原理。Thanks@ShrageSmilowitz好的,如果您创建一个包含
int.MaxValue
32位整数的数组,您将分配8GB内存。。。因此,这就是为什么您应该使用更小的缓冲区来构建结果@user626528早在2011年,当时.NET3.5占主导地位,这是最简单的答案。我同意你的看法,现在伊亚诺的答案好多了。我同意,这可能是最优雅的答案。但是值得注意的是,
Stream.CopyTo
仅在.NET4.+1中可用。当我为自己的不幸寻找解决办法时,我偶然发现了这个答案。我在第三方程序集中遇到了一个类问题(我想从中获取所有字节),该类派生自
Stream
,但其
Length
属性始终为零。我最初尝试了一种基于扩展方法的方法,但觉得它很笨拙;在复制之前,如何获得流?讨厌这些不完整的answers@GustavoBaiocchiCosta
yourBinaryReader.BaseStream
这不是构建-在.NET 4.0部分下的“stream”变量没有定义在任何地方。我认为这毕竟是一种优雅的方式
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..);

var size = new FileInfo(yourImagePath).Length;
byte[] allBytes = yourReader.ReadBytes(System.Convert.ToInt32(size));