Каков предпочтительный метод для создания байтового массива из входного потока?
Вот мое текущее решение с .NET 3.5.
Stream s;
byte[] b;
using (BinaryReader br = new BinaryReader(s))
{
b = br.ReadBytes((int)s.Length);
}
Это все-таки лучшая идея для чтения и записи фрагментов потока?
Ответы:
Это действительно зависит от того, можете ли вы доверять или нет
s.Length
. Для многих потоков вы просто не знаете, сколько будет данных. В таких случаях - и до .NET 4 - я бы использовал такой код:В .NET 4 и выше я бы использовал
Stream.CopyTo
, что в основном эквивалентно циклу в моем коде - создайтеMemoryStream
, вызовите,stream.CopyTo(ms)
а затем вернитеms.ToArray()
. Работа выполнена.Возможно, мне следует объяснить, почему мой ответ длиннее других.
Stream.Read
не гарантирует, что он прочитает все, о чем просил. Например, если вы читаете из сетевого потока, он может прочитать стоимость одного пакета и затем вернуться, даже если скоро будет больше данных.BinaryReader.Read
будет продолжаться до конца потока или указанного вами размера, но вы все равно должны знать размер для начала.Вышеуказанный метод будет продолжать читать (и копировать в
MemoryStream
), пока не закончатся данные. Затем он проситMemoryStream
вернуть копию данных в массиве. Если вы знаете размер, с которого хотите начать - или думаете, что знаете размер, не будучи уверенным - вы можете с самого началаMemoryStream
создать такой размер. Точно так же вы можете поставить проверку в конце, и если длина потока равна размеру буфера (возвращаемогоMemoryStream.GetBuffer
), то вы можете просто вернуть буфер. Таким образом, приведенный выше код не совсем оптимизирован, но, по крайней мере, будет правильным. Он не несет никакой ответственности за закрытие потока - вызывающий должен сделать это.Смотрите эту статью для получения дополнительной информации (и альтернативной реализации).
источник
16*1024
конкретно?Хотя ответ Джона верен, он переписывает код, который уже существует в
CopyTo
. Так что для .Net 4 используйте решение Sandip, но для предыдущей версии .Net используйте ответ Джона. Код Сандипа будет улучшен путем использования «использования» в качестве исключений,CopyTo
которые во многих ситуациях вполне вероятны и оставятMemoryStream
неиспользуемыми.источник
input
это ужеMemorySteam
и короткое замыкание. Я знаю, что было бы глупо, чтобы вызывающий игрок прошел,MemoryStream
но ...MemoryStream
то, имеет ли смысл оптимизация в вашем контексте, это сравнение времени, затраченного на миллионы преобразований типов, с временем, затрачиваемым на копирование того, который находитсяMemoryStream
в другойMemoryStream
.Просто хочу указать, что в случае, если у вас есть MemoryStream, у вас уже есть
memorystream.ToArray()
для этого.Кроме того, если вы имеете дело с потоками неизвестных или разных подтипов и можете получить a
MemoryStream
, вы можете ретранслировать указанный метод для этих случаев и по-прежнему использовать принятый ответ для других, например:источник
MemoryStream
s. Конечно, пример также явно неполон в том, как он использует неинициализированную переменную.stream.Seek(1L, SeekOrigin.Begin)
, прежде чем вызывать с готовностью, если поток является потоком памяти, вы получите на 1 байт больше, чем если бы это был любой другой поток. Если вызывающая сторона ожидает чтения с того места, где находится текущая позиция, до конца потока, то вы не должны использоватьCopyTo
илиToArray()
; В большинстве случаев это не будет проблемой, но если звонящий не знает об этом странном поведении, он будет сбит с толку.источник
только мои пара центов ... практика, которую я часто использую, состоит в том, чтобы организовать методы как этот как пользовательский помощник
добавить пространство имен в файл конфигурации и использовать его где угодно
источник
CopyTo
не было доступноStream
до 4.0.Вы можете просто использовать метод ToArray () класса MemoryStream, например,
источник
Вы даже можете сделать его более привлекательным с помощью расширений:
А затем вызовите его как обычный метод:
источник
Я получаю ошибку во время компиляции с кодом Боба (т.е. спрашивающего). Stream.Length является длинным, тогда как BinaryReader.ReadBytes принимает целочисленный параметр. В моем случае я не ожидаю иметь дело с потоками, достаточно большими, чтобы требовать высокой точности, поэтому я использую следующее:
источник
Если кому-то это нравится, вот решение .NET 4+, созданное как метод расширения без ненужного вызова Dispose для MemoryStream. Это безнадежно тривиальная оптимизация, но стоит отметить, что сбой при утилизации MemoryStream не является реальной ошибкой.
источник
С приведенным выше кодом все в порядке ... но вы столкнетесь с повреждением данных при отправке материалов по SMTP (если вам это нужно). Я изменил что-то еще, что поможет правильно отправить байт за байтом: '
источник
Создайте вспомогательный класс и ссылайтесь на него везде, где вы хотите его использовать.
источник
В пространстве имен RestSharp.Extensions есть метод ReadAsBytes. Внутри этого метода используется MemoryStream, и на этой странице есть тот же код, что и в некоторых примерах, но когда вы используете RestSharp, это самый простой способ.
источник
Вы можете использовать этот метод расширения.
источник
Это функция, которую я использую, протестировал и хорошо работал. Пожалуйста, имейте в виду, что «input» не должен быть нулевым, а «input.position» должен сбрасываться в «0» перед чтением, иначе это нарушит цикл чтения и ничего не будет прочитано для преобразования в массив.
источник
источник
я смог заставить его работать в одной строке:
как пояснил johnnyRose , вышеприведенный код будет работать только для MemoryStream
источник
localStream
неMemoryStream
? Этот код не удастся.localStream
кMemoryStream
, ноlocalStream
это неMemoryStream
, он будет не в состоянии . Этот код прекрасно скомпилируется, но может не работать во время выполнения, в зависимости от фактического типаlocalStream
. Вы не всегда можете произвольно привести базовый тип к дочернему типу; читайте больше здесь . Это еще один хороший пример, который объясняет, почему вы не всегда можете сделать это.