如何在 C# 中将 Stream 转换为 byte[]?

发布于 2024-07-26 06:37:22 字数 73 浏览 2 评论 0原文

在 C# 中是否有一种简单的方式或方法将 Stream 转换为 byte[]

Is there a simple way or method to convert a Stream into a byte[] in C#?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

回忆追雨的时光 2024-08-02 06:37:22

我知道的最短的解决方案:

using(var memoryStream = new MemoryStream())
{
  sourceStream.CopyTo(memoryStream);
  return memoryStream.ToArray();
}

The shortest solution I know:

using(var memoryStream = new MemoryStream())
{
  sourceStream.CopyTo(memoryStream);
  return memoryStream.ToArray();
}
扛起拖把扫天下 2024-08-02 06:37:22

调用下一个函数,如

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

Call next function like

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; 
        }
    }
}
墨洒年华 2024-08-02 06:37:22

我使用这个扩展类:

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

只需将该类复制到您的解决方案中,您就可以在每个流上使用它:

byte[] bytes = myStream.ReadAllBytes()

非常适合我的所有流并节省大量代码!
当然,如果需要,您可以修改此方法以使用此处的一些其他方法来提高性能,但我喜欢保持简单。

I use this extension class:

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

Just copy the class to your solution and you can use it on every stream:

byte[] bytes = myStream.ReadAllBytes()

Works great for all my streams and saves a lot of code!
Of course you can modify this method to use some of the other approaches here to improve performance if needed, but I like to keep it simple.

西瑶 2024-08-02 06:37:22

在 .NET Framework 4 及更高版本中,Stream 类具有可供您使用的内置 CopyTo 方法。

对于框架的早期版本,方便的辅助函数是:

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

编辑:最初我建议使用Jason的答案来支持Length属性的Stream。 但它有一个缺陷,因为它假设 Stream 将在一次 Read 中返回其所有内容,这不一定是正确的(不适用于 Socket例如。)我不知道 BCL 中是否有 Stream 实现的示例,它确实支持 Length 但可能以较短的块返回数据比您请求的要多,但由于任何人都可以继承 Stream ,这种情况很容易发生。

对于大多数情况,使用上述通用解决方案可能更简单,但假设您确实想直接读取 bigEnough 的数组:

byte[] b = new byte[bigEnough];
int r, offset;
while ((r = input.Read(b, offset, b.Length - offset)) > 0)
    offset += r;

也就是说,重复调用 Read 并移动您将存储数据的位置。

In .NET Framework 4 and later, the Stream class has a built-in CopyTo method that you can use.

For earlier versions of the framework, the handy helper function to have is:

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

Then use one of the above methods to copy to a MemoryStream and call GetBuffer on it:

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

Edit: originally I suggested using Jason's answer for a Stream that supports the Length property. But it had a flaw because it assumed that the Stream would return all its contents in a single Read, which is not necessarily true (not for a Socket, for example.) I don't know if there is an example of a Stream implementation in the BCL that does support Length but might return the data in shorter chunks than you request, but as anyone can inherit Stream this could easily be the case.

It's probably simpler for most cases to use the above general solution, but supposing you did want to read directly into an array that is bigEnough:

byte[] b = new byte[bigEnough];
int r, offset;
while ((r = input.Read(b, offset, b.Length - offset)) > 0)
    offset += r;

That is, repeatedly call Read and move the position you will be storing the data at.

娇柔作态 2024-08-02 06:37:22
Byte[] Content = new BinaryReader(file.InputStream).ReadBytes(file.ContentLength);
Byte[] Content = new BinaryReader(file.InputStream).ReadBytes(file.ContentLength);
以酷 2024-08-02 06:37:22
    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[] 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
暮凉 2024-08-02 06:37:22

好吧,也许我在这里遗漏了一些东西,但这就是我这样做的方式:

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

Ok, maybe I'm missing something here, but this is the way I do it:

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;
}
楠木可依 2024-08-02 06:37:22

如果您从移动设备或其他设备发布文件

    byte[] fileData = null;
    using (var binaryReader = new BinaryReader(Request.Files[0].InputStream))
    {
        fileData = binaryReader.ReadBytes(Request.Files[0].ContentLength);
    }

if you post a file from mobile device or other

    byte[] fileData = null;
    using (var binaryReader = new BinaryReader(Request.Files[0].InputStream))
    {
        fileData = binaryReader.ReadBytes(Request.Files[0].ContentLength);
    }
平安喜乐 2024-08-02 06:37:22
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;
}

需要稍微复杂一点的解决方案是 s.Length 超过 Int32.MaxValue。 但是,如果您需要将这么大的流读取到内存中,您可能需要考虑采用不同的方法来解决问题。

编辑:如果您的流不支持 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();
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;
}

A slightly more complicated solution is necesary is s.Length exceeds Int32.MaxValue. But if you need to read a stream that large into memory, you might want to think about a different approach to your problem.

Edit: If your stream does not support the Length property, modify using Earwicker's workaround.

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();
妥活 2024-08-02 06:37:22

快速而肮脏的技术:

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

测试:

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

我会问,为什么要将流读入 byte[],如果您希望复制流的内容,我可以建议使用 MemoryStream 并将输入流写入内存溪流。

Quick and dirty technique:

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

Test:

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

I would ask, why do you want to read a stream into a byte[], if you are wishing to copy the contents of a stream, may I suggest using MemoryStream and writing your input stream into a memory stream.

帅哥哥的热头脑 2024-08-02 06:37:22

您还可以尝试一次只读取部分内容并扩展返回的字节数组:

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

You could also try just reading in parts at a time and expanding the byte array being returned:

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;
}
拥抱影子 2024-08-02 06:37:22

“bigEnough”数组有点牵强。 当然,缓冲区需要“大”,但应用程序的正确设计应该包括事务和分隔符。 在此配置中,每个事务都有一个预设长度,因此您的数组将预期一定数量的字节并将其插入到正确大小的缓冲区中。 分隔符将确保事务完整性,并将在每个事务中提供。 为了使您的应用程序变得更好,您可以使用 2 个通道(2 个套接字)。 人们将传送固定长度的控制消息事务,该消息事务将包括关于要使用数据通道传输的数据事务的大小和序列号的信息。 接收器将确认缓冲区创建,然后才发送数据。
如果您无法控制流发送方,则需要多维数组作为缓冲区。 根据您对预期数据的估计,组件数组将足够小以便易于管理,并且足够大以便实用。 处理逻辑将在后续元素数组中寻找已知的开始分隔符,然后寻找结束分隔符。 一旦找到结束分隔符,将创建新的缓冲区来存储分隔符之间的相关数据,并且必须重组初始缓冲区以允许数据处理。

至于将流转换为字节数组的代码如下。

Stream s = yourStream;
int streamEnd = Convert.ToInt32(s.Length);
byte[] buffer = new byte[streamEnd];
s.Read(buffer, 0, streamEnd);

"bigEnough" array is a bit of a stretch. Sure, buffer needs to be "big ebough" but proper design of an application should include transactions and delimiters. In this configuration each transaction would have a preset length thus your array would anticipate certain number of bytes and insert it into correctly sized buffer. Delimiters would ensure transaction integrity and would be supplied within each transaction. To make your application even better, you could use 2 channels (2 sockets). One would communicate fixed length control message transactions that would include information about size and sequence number of data transaction to be transferred using data channel. Receiver would acknowledge buffer creation and only then data would be sent.
If you have no control over stream sender than you need multidimensional array as a buffer. Component arrays would be small enough to be manageable and big enough to be practical based on your estimate of expected data. Process logic would seek known start delimiters and then ending delimiter in subsequent element arrays. Once ending delimiter is found, new buffer would be created to store relevant data between delimiters and initial buffer would have to be restructured to allow data disposal.

As far as a code to convert stream into byte array is one below.

Stream s = yourStream;
int streamEnd = Convert.ToInt32(s.Length);
byte[] buffer = new byte[streamEnd];
s.Read(buffer, 0, streamEnd);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文