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@GustavoBaiocchiCostayourBinaryReader.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));