从流创建字节数组

时间:2008-10-21 13:42:55

标签: c# .net-3.5 inputstream

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

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

Stream s;
byte[] b;

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

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

16 个答案:

答案 0 :(得分:1189)

这实际取决于你是否可以信任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)然后返回{{ 1}}。完成工作。

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

上述方法将继续读取(并复制到ms.ToArray()),直到数据用完为止。然后它要求MemoryStream返回数组中的数据副本。如果您知道要开始的大小 - 或想想您知道大小,而不确定 - 您可以将MemoryStream构建为该大小。同样,您可以在结尾处进行检查,如果流的长度与缓冲区的大小相同(由MemoryStream.GetBuffer返回),那么您只需返回缓冲区即可。所以上面的代码并没有得到很好的优化,但至少是正确的。关闭流不承担任何责任 - 调用者应该这样做。

有关详细信息(以及替代实施),请参阅this article

答案 1 :(得分:654)

虽然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();
    }
}

答案 2 :(得分:95)

只是想指出,如果您有一个MemoryStream,那么您已经拥有memorystream.ToArray()

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

public static byte[] StreamToByteArray(Stream stream)
{
    if (stream is MemoryStream)
    {
        return ((MemoryStream)stream).ToArray();                
    }
    else
    {
        // Jon Skeet's accepted answer 
        return ReadFully(stream);
    }
}

答案 3 :(得分:61)

MemoryStream ms = new MemoryStream();
file.PostedFile.InputStream.CopyTo(ms);
var byts = ms.ToArray();
ms.Dispose();

答案 4 :(得分:47)

只是我的几分钱...我经常使用的做法是将这样的方法组织为自定义助手

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

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

答案 5 :(得分:10)

你甚至可以通过扩展程序使它变得更加漂亮:

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()

答案 6 :(得分:8)

您可以简单地使用MemoryStream类的ToArray()方法,例如-

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

答案 7 :(得分:7)

我的Bob(即提问者)代码出现编译时错误。 Stream.Length是long,而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);
}

答案 8 :(得分:3)

上面的那个是好的...但是当您通过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;
        }'

答案 9 :(得分:2)

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

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

答案 10 :(得分:2)

如果有人喜欢它,这是一个仅.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();
    }
}

答案 11 :(得分:1)

在名称空间RestSharp.Extensions中,有方法ReadAsBytes。在该方法内部使用MemoryStream,并且有与该页面上某些示例中相同的代码,但是当您使用RestSharp时,这是最简单的方法。

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

答案 12 :(得分:0)

您可以使用此扩展方法。

public static class StreamExtensions
{
    public static byte[] ToByteArray(this Stream stream)
    {
        var bytes = new List<byte>();

        int b;
        while ((b = stream.ReadByte()) != -1)
            bytes.Add((byte)b);

        return bytes.ToArray();
    }
}

答案 13 :(得分:0)

这是我正在使用,测试和运行良好的功能。 请记住,“ 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;
        }
    }

答案 14 :(得分:-1)

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();
            }
        }            
    }

答案 15 :(得分:-4)

我能够让它在一条线上工作:

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

johnnyRose澄清,上面的代码仅适用于MemoryStream