从流中创建一个字节数组

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

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

Stream s;
byte[] b;

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

读取和写入数据流块是否更好?


这真的取决于你是否可以信任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返回),那么你可以返回缓冲区。 所以上面的代码没有被优化,但至少是正确的。 它不承担任何关闭流的责任 - 调用者应该这样做。

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


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

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

只是想指出,如果你有一个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);
    }
}
链接地址: http://www.djcxy.com/p/34885.html

上一篇: Creating a byte array from a stream

下一篇: Ideal way to set global uncaught exception Handler in Android