从流创建字节数组

从输入流创建字节数组的首选方法是什么?

这是我目前使用的解决方案。NET 3.5。

Stream s;byte[] b;
using (BinaryReader br = new BinaryReader(s)){b = br.ReadBytes((int)s.Length);}

读取和写入流的大块是否仍然是一个更好的主意?

1084345 次浏览

这实际上取决于您是否可以信任s.Length。对于许多流,您只是不知道会有多少数据。在这种情况下-在. NET 4之前-我会使用这样的代码:

public static byte[] ReadFully(Stream input){byte[] buffer = new byte[16*1024];using (MemoryStream ms = new MemoryStream()){int read;while ((read = input.Read(buffer, 0, buffer.Length)) > 0){ms.Write(buffer, 0, read);}return ms.ToArray();}}

对于. NET 4及更高版本,我将使用#0,它基本上相当于我代码中的循环-创建MemoryStream,调用stream.CopyTo(ms)然后返回ms.ToArray()。工作完成。

我也许应该解释一下为什么我的答案比其他答案长。#0不能保证它会读取它所要求的所有内容。例如,如果你从网络流中读取,它可能会读取一个数据包的价值,然后返回,即使很快会有更多的数据。#1会一直持续到流的末尾或你指定的大小,但你仍然必须知道开始的大小。

上面的方法将继续读取(并复制到MemoryStream),直到数据用完。然后它要求MemoryStream返回数组中数据的副本。如果你知道开始的大小-或者认为你知道大小,但不确定-你可以将MemoryStream构造为开始时的大小。同样,你可以在末尾进行检查,如果流的长度与缓冲区的大小相同(由#3返回),那么你可以只返回缓冲区。所以上面的代码不是很优化,但至少是正确的。它不承担关闭流的任何责任-调用者应该这样做。

有关更多信息(和替代实现),请参阅这篇文章

只是想指出,如果你有一个MemoryStream,你已经有了memorystream.ToArray()

此外,如果您正在处理未知或不同子类型的流,并且您可以收到MemoryStream,则可以针对这些情况中继上述方法,并且仍然对其他情况使用接受的答案,如下所示:

public static byte[] StreamToByteArray(Stream stream){if (stream is MemoryStream){return ((MemoryStream)stream).ToArray();}else{// Jon Skeet's accepted answerreturn ReadFully(stream);}}
MemoryStream ms = new MemoryStream();file.PostedFile.InputStream.CopyTo(ms);var byts = ms.ToArray();ms.Dispose();

我在Bob的(即提问者的)代码中得到一个编译时错误。Stream. L的长度很长,而BinaryReader. ReadBytes需要一个整数参数。在我的情况下,我不希望处理足够大到需要长精度的Streams,所以我使用以下内容:

Stream s;byte[] b;
if (s.Length > int.MaxValue) {throw new Exception("This stream is larger than the conversion algorithm can currently handle.");}
using (var br = new BinaryReader(s)) {b = br.ReadBytes((int)s.Length);}

虽然Jon的答案是正确的,但他正在重写CopyTo中已经存在的代码。因此对于. Net 4使用Sandip的解决方案,但对于以前的版本. Net使用Jon的答案。Sandip的代码将通过使用“使用”来改进,因为在许多情况下,CopyTo中的异常很可能并且不会处理MemoryStream

public static byte[] ReadFully(Stream input){using (MemoryStream ms = new MemoryStream()){input.CopyTo(ms);return ms.ToArray();}}

你甚至可以用扩展让它更漂亮:

namespace Foo{public static class Extensions{public static byte[] ToByteArray(this Stream stream){using (stream){using (MemoryStream memStream = new MemoryStream()){stream.CopyTo(memStream);return memStream.ToArray();}}}}}

然后将其称为常规方法:

byte[] arr = someStream.ToByteArray()

上面的那个可以……但是当你通过SMTP发送东西时(如果你需要)会遇到数据损坏。我已经修改了其他有助于正确发送字节对字节的东西:'

using System;using System.IO;
private static byte[] ReadFully(string input){FileStream sourceFile = new FileStream(input, FileMode.Open); //Open streamerBinaryReader binReader = new BinaryReader(sourceFile);byte[] output = new byte[sourceFile.Length]; //create byte array of size filefor (long i = 0; i < sourceFile.Length; i++)output[i] = binReader.ReadByte(); //read until donesourceFile.Close(); //dispose streamerbinReader.Close(); //dispose readerreturn output;}'

只是我的几美分…我经常使用的练习是将这样的方法组织为自定义助手

public static class StreamHelpers{public static byte[] ReadFully(this Stream input){using (MemoryStream ms = new MemoryStream()){input.CopyTo(ms);return ms.ToArray();}}}

将命名空间添加到配置文件并在您希望的任何地方使用它

我能够使它在单行上工作:

byte [] byteArr= ((MemoryStream)localStream).ToArray();

正如Johnny Rose所澄清的,上面的代码只适用于MemoryStream

将两个投票最多的答案组合成一个扩展方法:

public static byte[] ToByteArray(this Stream stream){if (stream is MemoryStream)return ((MemoryStream)stream).ToArray();else{using MemoryStream ms = new();stream.CopyTo(ms);return ms.ToArray();}}

您可以使用此扩展方法。

public static class StreamExtensions{public static byte[] ToByteArray(this Stream stream){var bytes = new List<byte>();
int b;
// -1 is a special value that mark the end of the streamwhile ((b = stream.ReadByte()) != -1)bytes.Add((byte)b);
return bytes.ToArray();}}

您可以简单地使用MemoryStream类的ToArray()方法,对于ex-

MemoryStream ms = (MemoryStream)dataInStream;byte[] imageBytes = ms.ToArray();

创建一个辅助类并在您希望使用它的任何地方引用它。

public static class StreamHelpers{public static byte[] ReadFully(this Stream input){using (MemoryStream ms = new MemoryStream()){input.CopyTo(ms);return ms.ToArray();}}}

如果有人喜欢它,这里有一个. NET 4+唯一的解决方案,它形成为扩展方法,没有对MemoryStream进行不必要的Dispose调用。这是一个无可救药的琐碎优化,但值得注意的是,未能处理MemoryStream并不是真正的失败。

public static class StreamHelpers{public static byte[] ReadFully(this Stream input){var ms = new MemoryStream();input.CopyTo(ms);return ms.ToArray();}}

这是我正在使用、测试和运行良好的功能。请记住,“输入”不应为空,“input.position”应在读取前重置为“0”,否则将中断读取循环,并且不会读取任何内容以转换为数组。

    public static byte[] StreamToByteArray(Stream input){if (input == null)return null;byte[] buffer = new byte[16 * 1024];input.Position = 0;using (MemoryStream ms = new MemoryStream()){int read;while ((read = input.Read(buffer, 0, buffer.Length)) > 0){ms.Write(buffer, 0, read);}byte[] temp = ms.ToArray();
return temp;}}

在命名空间RESTSharp. Ex的有方法ReadAsBytes。在这个方法里面使用了MemoryStream,并且有与此页面上的一些示例相同的代码,但是当您使用RESTSharp时,这是最简单的方法。

using RestSharp.Extensions;var byteArray = inputStream.ReadAsBytes();

如果流支持长度属性,可以直接创建字节数组。优点是MemoryStream.ToArray创建了两次数组。另外,缓冲区中可能有一些未使用的额外字节。此解决方案分配所需的确切数组。如果流不支持长度属性,它将抛出NotSupportedException异常。

还值得注意的是,数组不能大于int. MaxValue。

public static async Task<byte[]> ToArrayAsync(this Stream stream){var array = new byte[stream.Length];await stream.ReadAsync(array, 0, (int)stream.Length);return array;}

根据流是否支持查找在两个版本之间切换的完整代码。

/// <summary>/// Converts stream to byte array./// </summary>/// <param name="stream">Stream</param>/// <returns>Binary data from stream in an array</returns>public static async Task<byte[]> ToArrayAsync(this Stream stream){if (!stream.CanRead){throw new AccessViolationException("Stream cannot be read");}
if (stream.CanSeek){return await ToArrayAsyncDirect(stream);}else{return await ToArrayAsyncGeneral(stream);}}
private static async Task<byte[]> ToArrayAsyncGeneral(Stream stream){using (var memoryStream = new MemoryStream()){await stream.CopyToAsync(memoryStream);return memoryStream.ToArray();}}
private static async Task<byte[]> ToArrayAsyncDirect(Stream stream){var array = new byte[stream.Length];await stream.ReadAsync(array, 0, (int)stream.Length);return array;}

由于这个答案没有现代(即异步)版本,这是我为此目的使用的扩展方法:

public static async Task<byte[]> ReadAsByteArrayAsync(this Stream source){// Optimizationif (source is MemoryStream memorySource)return memorySource.ToArray();
using var memoryStream = new MemoryStream();await source.CopyToAsync(memoryStream);return memoryStream.ToArray();}

优化是基于#0的源代码调用一些内部方法的事实。