关于inputstream:如何在C#中将Stream转换为byte []?

How to convert an Stream into a byte[] in C#?

本问题已经有最佳答案,请猛点这里访问。

有没有一种简单的方法或方法可以将c中的Stream转换成byte[]


我知道最短的解决方案:

1
2
3
4
5
using(var memoryStream = new MemoryStream())
{
  sourceStream.CopyTo(memoryStream);
  return memoryStream.ToArray();
}


调用下一个函数

1
byte[] m_Bytes = StreamHelper.ReadToEnd (mystream);

功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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;
            }
        }
    }


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

对于早期版本的框架,要具有的方便助手功能是:

1
2
3
4
5
6
7
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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中是否有支持LengthStream实现的示例,但可能返回较短的数据块。你要求的,但是任何人都可以继承Stream,这很容易发生。

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

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

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


1
2
3
4
    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


我使用这个扩展类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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();
        }
    }
}

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

1
byte[] bytes = myStream.ReadAllBytes()

对我所有的流都很有用,并且节省了很多代码!当然,如果需要的话,您可以修改这个方法来使用这里的其他一些方法来提高性能,但是我喜欢保持简单。


1
Byte[] Content = new BinaryReader(file.InputStream).ReadBytes(file.ContentLength);


好吧,也许我错过了一些东西,但我就是这样做的:

1
2
3
4
5
6
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;
}


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

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


快速肮脏技术:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    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;
    }

测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
    static void Main(string[] args)
    {
        byte[] data;
        string path = @"C:\Windows\System32
otepad.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);
    }

我会问,如果您希望复制流的内容,为什么要将流读取到字节[],我建议您使用memory stream并将输入流写入内存流。


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;
}

1
2
3
4
5
6
7
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的变通方法进行修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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();


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

至于将流转换为字节数组的代码,请参阅下面的代码。

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