从输入流创建字节数组的首选方法是什么?
这是我当前使用.NET 3.5的解决方案。
Stream s;
byte[] b;
using (BinaryReader br = new BinaryReader(s))
{
b = br.ReadBytes((int)s.Length);
}
读写流的块还是更好的主意吗?
从输入流创建字节数组的首选方法是什么?
这是我当前使用.NET 3.5的解决方案。
Stream s;
byte[] b;
using (BinaryReader br = new BinaryReader(s))
{
b = br.ReadBytes((int)s.Length);
}
读写流的块还是更好的主意吗?
Answers:
这实际上取决于您是否可以信任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及更高版本中,我将使用Stream.CopyTo
,它基本上等效于代码中的循环-创建MemoryStream
,调用stream.CopyTo(ms)
然后返回ms.ToArray()
。任务完成。
我也许应该解释为什么我的答案比其他答案更长。Stream.Read
不保证它将读取要求的所有内容。例如,如果您正在从网络流中读取数据,即使很快会有更多数据,它也可能读取一个数据包的价值然后返回。BinaryReader.Read
会一直持续到流的结尾或您指定的大小,但是您仍然必须知道开始的大小。
上面的方法将继续读取(并复制到中MemoryStream
),直到用完数据为止。然后,它要求传MemoryStream
回阵列中资料的副本。如果你知道的大小-开始,或认为你知道的大小,但是不肯定的-你可以构造MemoryStream
是该尺寸的开始。同样,您可以在末尾进行检查,如果流的长度与缓冲区的大小相同(由返回MemoryStream.GetBuffer
),则可以仅返回缓冲区。因此,上面的代码没有得到最优化,但至少是正确的。它不承担关闭流的任何责任-调用者应该这样做。
请参阅本文以获取更多信息(和替代实现)。
16*1024
特别吗?
虽然乔恩的答案是正确的,但他正在重写中已经存在的代码CopyTo
。因此,对于.Net 4,请使用Sandip解决方案,而对于.Net的早期版本,请使用Jon的答案。Sandip的代码将通过使用“ using”进行改进,因为CopyTo
在许多情况下,出现异常的可能性很大,并且MemoryStream
不会处理掉。
public static byte[] ReadFully(Stream input)
{
using (MemoryStream ms = new MemoryStream())
{
input.CopyTo(ms);
return ms.ToArray();
}
}
input
已经MemorySteam
短路。我知道通过呼叫者MemoryStream
但通过呼叫者是愚蠢的……
MemoryStream
那么的优化是否有道理在您的上下文是做数以百万计的类型转换的反对所花费的时间所花费的时间复制一个,这是一个比较MemoryStream
成另一个MemoryStream
。
只是要指出,以防万一您已经拥有一个MemoryStream memorystream.ToArray()
。
另外,如果您正在处理未知或不同子类型的流,并且可以收到MemoryStream
,则可以在上述情况下继续使用上述方法,而对于其他情况仍可以使用可接受的答案,例如:
public static byte[] StreamToByteArray(Stream stream)
{
if (stream is MemoryStream)
{
return ((MemoryStream)stream).ToArray();
}
else
{
// Jon Skeet's accepted answer
return ReadFully(stream);
}
}
MemoryStream
s的流。当然,该示例在使用未初始化变量方面也显然是不完整的。
stream.Seek(1L, SeekOrigin.Begin)
,则在您进行可读调用之前,如果该流是内存流,则比任何其他流多1个字节。如果调用者希望从当前位置读取到流的末尾,则不得使用CopyTo
或ToArray()
; 在大多数情况下,这不是问题,但是如果呼叫者不知道这种古怪的行为,则会感到困惑。
MemoryStream ms = new MemoryStream();
file.PostedFile.InputStream.CopyTo(ms);
var byts = ms.ToArray();
ms.Dispose();
只是我的几分钱...我经常使用的做法是将这样的方法组织为自定义帮助程序
public static class StreamHelpers
{
public static byte[] ReadFully(this Stream input)
{
using (MemoryStream ms = new MemoryStream())
{
input.CopyTo(ms);
return ms.ToArray();
}
}
}
将名称空间添加到配置文件中,并在您希望的任何地方使用它
CopyTo
无法使用,Stream
直到4.0 才可用。
您可以简单地使用MemoryStream类的ToArray()方法,例如
MemoryStream ms = (MemoryStream)dataInStream;
byte[] imageBytes = 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()
我收到鲍勃(即提问者)的代码的编译时错误。Stream.Length是一个长整数,而BinaryReader.ReadBytes需要一个整数参数。就我而言,我并不期望处理足够大的流以至于需要长精度,因此我使用以下方法:
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);
}
上面的一个是可以的...但是当您通过SMTP发送邮件时(如果需要),您将遇到数据损坏的情况。我已更改为其他有助于正确发送字节对字节的内容:'
using System;
using System.IO;
private static byte[] ReadFully(string input)
{
FileStream sourceFile = new FileStream(input, FileMode.Open); //Open streamer
BinaryReader binReader = new BinaryReader(sourceFile);
byte[] output = new byte[sourceFile.Length]; //create byte array of size file
for (long i = 0; i < sourceFile.Length; i++)
output[i] = binReader.ReadByte(); //read until done
sourceFile.Close(); //dispose streamer
binReader.Close(); //dispose reader
return output;
}'
创建一个帮助器类,并在您想使用它的任何地方引用它。
public static class StreamHelpers
{
public static byte[] ReadFully(this Stream input)
{
using (MemoryStream ms = new MemoryStream())
{
input.CopyTo(ms);
return ms.ToArray();
}
}
}
在名称空间RestSharp.Extensions中,有方法ReadAsBytes。在此方法内部使用MemoryStream,并且有与该页面上某些示例中相同的代码,但是当您使用RestSharp时,这是最简单的方法。
using RestSharp.Extensions;
var byteArray = inputStream.ReadAsBytes();
这是我正在使用,测试和运行良好的功能。请记住,“ input”不应为null,“ 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;
}
}
public static byte[] ToByteArray(Stream stream)
{
if (stream is MemoryStream)
{
return ((MemoryStream)stream).ToArray();
}
else
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
}
我能够使它在一行上工作:
byte [] byteArr= ((MemoryStream)localStream).ToArray();
如johnnyRose所阐明的,以上代码仅适用于MemoryStream
localStream
不是,该MemoryStream
怎么办?此代码将失败。
localStream
的MemoryStream
,但是localStream
是不是一个MemoryStream
,它就会失败。这段代码可以很好地编译,但是根据的实际类型,它可能会在运行时失败localStream
。您不能总是将基本类型任意转换为子类型。在这里阅读更多。这是另一个很好的例子,它说明了为什么不能总是这样做。