Создание массива байтов из потока

Каков предпочтительный метод для создания байтового массива из входного потока?

Вот мое текущее решение с .NET 3.5.

Stream s;
byte[] b;

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

Разве еще лучше читать и писать куски потока?

Ответ 1

Это действительно зависит от того, можете ли вы доверять 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 я бы использовал Stream.CopyTo, который в основном эквивалентен циклу в моем коде - создайте MemoryStream, вызовите stream.CopyTo(ms) а затем верните ms.ToArray(). Работа выполнена.

Возможно, мне следует объяснить, почему мой ответ длиннее других. Stream.Read не гарантирует, что он будет читать все, что просил. Например, если вы читаете из сетевого потока, он может прочитать один пакет и затем вернуться, даже если скоро будет больше данных. BinaryReader.Read будет продолжать работать до конца потока или указанного вами размера, но вы все равно должны знать размер для начала.

Вышеуказанный метод будет продолжать читать (и копировать в MemoryStream), пока не закончатся данные. Затем он просит MemoryStream вернуть копию данных в массиве. Если вы знаете размер, с которого начинаете - или думаете, что знаете размер, не будучи уверенным - вы можете создать MemoryStream таким, чтобы он начинался с этого размера. Аналогичным образом вы можете поставить проверку в конце, и если длина потока равна размеру буфера (возвращаемого MemoryStream.GetBuffer), то вы можете просто вернуть буфер. Таким образом, приведенный выше код не совсем оптимизирован, но, по крайней мере, будет правильным. Он не несет никакой ответственности за закрытие потока - вызывающий должен сделать это.

Смотрите эту статью для получения дополнительной информации (и альтернативной реализации).

Ответ 2

Пока Джон отвечает правильно, он переписывает код, который уже существует в CopyTo. Так что для .Net 4 используйте решение Sandip, а для предыдущей версии .Net используйте Jon answer. Код Sandip был бы улучшен путем использования "использования", так как исключения в CopyTo, во многих ситуациях, весьма вероятны и оставили бы MemoryStream не утилизированным.

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

Ответ 3

Просто хочу указать, что если у вас есть MemoryStream, у вас уже есть memorystream.ToArray().

Кроме того, если вы имеете дело с потоками неизвестных или разных подтипов, и вы можете получить MemoryStream, вы можете передать упомянутый метод для этих случаев и по-прежнему использовать принятый ответ для других, например:

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

Ответ 4

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

Ответ 5

просто мои пары центов... практика, которую я часто использую, состоит в том, чтобы организовывать такие методы как пользовательский помощник

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

добавить пространство имен в файл конфигурации и использовать его в любом месте

Ответ 6

Вы даже можете сделать его более привлекательным с расширениями:

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

Ответ 7

Вы можете просто использовать метод ToArray() класса MemoryStream для ex-

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

Ответ 8

Я получаю ошибку времени компиляции с кодом Боба (то есть вопросника). Stream.Length длинна, тогда как BinaryReader.ReadBytes принимает целочисленный параметр. В моем случае я не ожидаю иметь дело с потоками, достаточно большими, чтобы требовать большой точности, поэтому я использую следующее:

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

Ответ 9

Один из них в порядке... но вы столкнетесь с повреждением данных при отправке файлов через 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;
        }'

Ответ 10

Создайте вспомогательный класс и ссылайтесь на него везде, где вы хотите его использовать.

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

Ответ 11

В случае, если кому-то это нравится, вот решение .NET 4+ only, сформированное как метод расширения без ненужного вызова Dispose для MemoryStream. Это безнадежно тривиальная оптимизация, но стоит отметить, что неудача в утилизации MemoryStream не является реальной ошибкой.

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

Ответ 12

В пространстве имен RestSharp.Extensions есть метод ReadAsBytes. Внутри этого метода используется MemoryStream, и на этой странице есть тот же код, что и в некоторых примерах, но когда вы используете RestSharp, это самый простой способ.

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

Ответ 13

Вы можете использовать этот метод расширения.

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

Ответ 14

Это функция, которую я использую, протестировал и хорошо работал. пожалуйста, имейте в виду, что "input" не должен быть нулевым, а "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;
        }
    }

Ответ 15

это поможет вам:

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

Ответ 16

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

Ответ 17

Мне удалось заставить его работать в одной строке:

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

как выяснено johnnyRose, выше код будет работать только для MemoryStream