如何将stream转换为C#中的字节?
有没有一种简单的方法或方法在C#中将Stream
转换为byte[]
?
调用下一个函数
byte[] m_Bytes = StreamHelper.ReadToEnd (mystream);
function:
public static byte[] ReadToEnd(System.IO.Stream stream) { long originalPosition = 0; if(stream.CanSeek) { originalPosition = stream.Position; stream.Position = 0; } try { byte[] readBuffer = new byte[4096]; int totalBytesRead = 0; int bytesRead; while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0) { totalBytesRead += bytesRead; if (totalBytesRead == readBuffer.Length) { int nextByte = stream.ReadByte(); if (nextByte != -1) { byte[] temp = new byte[readBuffer.Length * 2]; Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length); Buffer.SetByte(temp, totalBytesRead, (byte)nextByte); readBuffer = temp; totalBytesRead++; } } } byte[] buffer = readBuffer; if (readBuffer.Length != totalBytesRead) { buffer = new byte[totalBytesRead]; Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead); } return buffer; } finally { if(stream.CanSeek) { stream.Position = originalPosition; } } }
我知道的最短的解决scheme:
using(var memoryStream = new MemoryStream()) { sourceStream.CopyTo(memoryStream); return memoryStream.ToArray(); }
在.NET Framework 4和更高版本中, Stream
类具有可以使用的内置CopyTo
方法。
对于早期版本的框架,便利的帮手function是:
public static void CopyStream(Stream input, Stream output) { byte[] b = new byte[32768]; int r; while ((r = input.Read(b, 0, b.Length)) > 0) output.Write(b, 0, r); }
然后使用上述方法之一复制到一个MemoryStream
并调用GetBuffer
:
var file = new FileStream("c:\\foo.txt", FileMode.Open); var mem = new MemoryStream(); // If using .NET 4 or later: file.CopyTo(mem); // Otherwise: CopyStream(file, mem); // getting the internal buffer (no additional copying) byte[] buffer = mem.GetBuffer(); long length = mem.Length; // the actual length of the data // (the array may be longer) // if you need the array to be exactly as long as the data byte[] truncated = mem.ToArray(); // makes another copy
编辑:最初我build议使用贾森的答案为支持Length
属性的Stream
。 但是它有一个缺陷,因为它假设Stream
将会在一个Read
返回所有的内容,这不一定是真的(例如不是一个Socket
)。我不知道是否有一个Stream
实现的例子在支持Length
的BCL中,但是可能会以比您请求的更短的块的forms返回数据,但是由于任何人都可以inheritanceStream
因此很容易出现这种情况。
对于大多数情况来说,使用上面的一般解决scheme可能会更简单,但是假设您想直接读取一个bigEnough
数组:
byte[] b = new byte[bigEnough]; int r, offset; while ((r = input.Read(b, offset, b.Length - offset)) > 0) offset += r;
也就是说,重复调用Read
移动你要存储数据的位置。
byte[] buf; // byte array Stream stream=Page.Request.InputStream; //initialise new stream buf = new byte[stream.Length]; //declare arraysize stream.Read(buf, 0, buf.Length); // read from stream to byte array
Byte[] Content = new BinaryReader(file.InputStream).ReadBytes(file.ContentLength);
我使用这个扩展类:
public static class StreamExtensions { public static byte[] ReadAllBytes(this Stream instream) { if (instream is MemoryStream) return ((MemoryStream) instream).ToArray(); using (var memoryStream = new MemoryStream()) { instream.CopyTo(memoryStream); return memoryStream.ToArray(); } } }
只需将该课程复制到您的解决scheme中,即可在每个stream中使用它:
byte[] bytes = myStream.ReadAllBytes()
适用于我所有的stream,并节省了大量的代码! 当然你可以修改这个方法来使用其他一些方法来提高性能,如果需要的话,但是我想保持简单。
好吧,也许我在这里错过了一些东西,但这是我做的方式:
public static Byte[] ToByteArray(this Stream stream) { Int32 length = stream.Length > Int32.MaxValue ? Int32.MaxValue : Convert.ToInt32(stream.Length); Byte[] buffer = new Byte[length]; stream.Read(buffer, 0, length); return buffer; }
快速和肮脏的技术:
static byte[] StreamToByteArray(Stream inputStream) { if (!inputStream.CanRead) { throw new ArgumentException(); } // This is optional if (inputStream.CanSeek) { inputStream.Seek(0, SeekOrigin.Begin); } byte[] output = new byte[inputStream.Length]; int bytesRead = inputStream.Read(output, 0, output.Length); Debug.Assert(bytesRead == output.Length, "Bytes read from stream matches stream length"); return output; }
testing:
static void Main(string[] args) { byte[] data; string path = @"C:\Windows\System32\notepad.exe"; using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read)) { data = StreamToByteArray(fs); } Debug.Assert(data.Length > 0); Debug.Assert(new FileInfo(path).Length == data.Length); }
我会问,为什么你想读stream到一个字节[],如果你想复制一个stream的内容,我可以build议使用MemoryStream并将你的inputstream写入一个内存stream。
如果您从移动设备或其他文件发布文件
byte[] fileData = null; using (var binaryReader = new BinaryReader(Request.Files[0].InputStream)) { fileData = binaryReader.ReadBytes(Request.Files[0].ContentLength); }
Stream s; int len = (int)s.Length; byte[] b = new byte[len]; int pos = 0; while((r = s.Read(b, pos, len - pos)) > 0) { pos += r; }
稍微复杂的解决scheme是必要的是s.Length
超过Int32.MaxValue
。 但是,如果您需要阅读大量内容的stream,则可能需要考虑针对您的问题的不同方法。
编辑:如果您的stream不支持Length
属性,请使用Earwicker的解决方法进行修改。
public static class StreamExtensions { // Credit to Earwicker public static void CopyStream(this Stream input, Stream output) { byte[] b = new byte[32768]; int r; while ((r = input.Read(b, 0, b.Length)) > 0) { output.Write(b, 0, r); } } } [...] Stream s; MemoryStream ms = new MemoryStream(); s.CopyStream(ms); byte[] b = ms.GetBuffer();
您也可以尝试一次读取部分内容,然后展开返回的字节数组:
public byte[] StreamToByteArray(string fileName) { byte[] total_stream = new byte[0]; using (Stream input = File.Open(fileName, FileMode.Open, FileAccess.Read)) { byte[] stream_array = new byte[0]; // Setup whatever read size you want (small here for testing) byte[] buffer = new byte[32];// * 1024]; int read = 0; while ((read = input.Read(buffer, 0, buffer.Length)) > 0) { stream_array = new byte[total_stream.Length + read]; total_stream.CopyTo(stream_array, 0); Array.Copy(buffer, 0, stream_array, total_stream.Length, read); total_stream = stream_array; } } return total_stream; }
“bigEnough”数组有点儿延伸。 当然,缓冲区需要“很大”,但是正确的应用程序devise应该包括事务和分隔符。 在这个configuration中,每个事务将有一个预设的长度,因此你的数组将预期一定数量的字节并将其插入正确大小的缓冲区中。 分隔符将确保交易完整性,并将在每笔交易中提供。 为了使您的应用程序更好,您可以使用2个通道(2个插槽)。 一个人可以通信固定长度的控制消息交易,其中将包括关于使用数据信道传送的数据交易的大小和序列号的信息。 Receiver将会确认缓冲区的创build,然后才会发送数据。 如果您无法控制stream发送方,则需要使用multidimensional array作为缓冲区。 组件arrays将足够小以便于pipe理,并且足够大以便根据对预期数据的估计进行实践。 进程逻辑会寻找已知的起始分隔符,然后在随后的元素数组中结束分隔符。 一旦发现结束分隔符,将创build新的缓冲区来存储分隔符之间的相关数据,并且初始缓冲区将不得不重构以允许数据处置。
至于将stream转换为字节数组的代码如下所示。
Stream s = yourStream; int streamEnd = Convert.ToInt32(s.Length); byte[] buffer = new byte[streamEnd]; s.Read(buffer, 0, streamEnd);