Есть ли элегантный способ эмулировать метод StreamReader.ReadToEnd
с помощью BinaryReader
? Возможно, чтобы поместить все байты в массив байтов?
Я сделаю это:
read1.ReadBytes((int)read1.BaseStream.Length);
... но должен быть лучший способ.
Есть ли элегантный способ эмулировать метод StreamReader.ReadToEnd
с помощью BinaryReader
? Возможно, чтобы поместить все байты в массив байтов?
Я сделаю это:
read1.ReadBytes((int)read1.BaseStream.Length);
... но должен быть лучший способ.
Просто сделайте:
byte[] allData = read1.ReadBytes(int.MaxValue);
В документации говорится, что он будет читать все байты пока не будет достигнут конец потока.
Хотя это кажется элегантным, и в документации указано, что это будет работать, фактическая реализация (проверенная в .NET 2, 3.5 и 4) выделяет для данных полноразмерный массив байтов, который вероятно вызовет OutOfMemoryException
в 32-битной системе.
Поэтому я бы сказал, что на самом деле элегантного способа не существует.
Вместо этого я бы рекомендовал следующий вариант ответа @iano. Этот вариант не зависит от .NET 4:
Создайте метод расширения для BinaryReader
(или Stream
, код одинаков для обоих).
public static byte[] ReadAllBytes(this BinaryReader reader)
{
const int bufferSize = 4096;
using (var ms = new MemoryStream())
{
byte[] buffer = new byte[bufferSize];
int count;
while ((count = reader.Read(buffer, 0, buffer.Length)) != 0)
ms.Write(buffer, 0, count);
return ms.ToArray();
}
}
int.MaxValue
32-битных целых чисел, вы будете выделять 8 ГБ памяти ... вот почему вы должны строить результаты, используя меньшие буферы!
- person Scott Rippey; 12.12.2014
read1.ReadBytes((int)read1.BaseStream.Length);
кажется не такой уж плохой, чтобы оправдать метод расширения. Пока Microsoft не добавляет ReadToEnd в BinaryReader (который присутствует в StreamReader), я бы придерживался однострочника.
- person LRMAAX; 23.06.2020
Не существует простого способа сделать это с помощью BinaryReader. Если вы не знаете количество, которое вам нужно прочитать заранее, лучше использовать MemoryStream:
public byte[] ReadAllBytes(Stream stream)
{
using (var ms = new MemoryStream())
{
stream.CopyTo(ms);
return ms.ToArray();
}
}
Чтобы избежать дополнительной копии при вызове ToArray()
, вместо этого вы можете вернуть Position
и буфер через GetBuffer()
.
Stream.CopyTo
доступен только в .NET 4.
- person Scott Rippey; 09.04.2012
Stream
, но его свойство Length
всегда было равно нулю. Сначала я попробовал подход, основанный на методах расширения, но он показался мне громоздким.
- person Wai Ha Lee; 04.03.2015
yourBinaryReader.BaseStream
- person jtate; 05.11.2018
binaryReader.BaseStream.Length
был доступен тогда, но теперь мы можем использовать его без необходимости создавать новый MemoryStream
! :)
- person Mark A. Donohoe; 18.01.2021
Чтобы скопировать содержимое потока в другой, я решил прочитать «некоторые» байты, пока не будет достигнут конец файла:
private const int READ_BUFFER_SIZE = 1024;
using (BinaryReader reader = new BinaryReader(responseStream))
{
using (BinaryWriter writer = new BinaryWriter(File.Open(localPath, FileMode.Create)))
{
int byteRead = 0;
do
{
byte[] buffer = reader.ReadBytes(READ_BUFFER_SIZE);
byteRead = buffer.Length;
writer.Write(buffer);
byteTransfered += byteRead;
} while (byteRead == READ_BUFFER_SIZE);
}
}
Другой подход к этой проблеме заключается в использовании методов расширения C#:
public static class StreamHelpers
{
public static byte[] ReadAllBytes(this BinaryReader reader)
{
// Pre .Net version 4.0
const int bufferSize = 4096;
using (var ms = new MemoryStream())
{
byte[] buffer = new byte[bufferSize];
int count;
while ((count = reader.Read(buffer, 0, buffer.Length)) != 0)
ms.Write(buffer, 0, count);
return ms.ToArray();
}
// .Net 4.0 or Newer
using (var ms = new MemoryStream())
{
stream.CopyTo(ms);
return ms.ToArray();
}
}
}
Использование этого подхода позволит использовать как повторно используемый, так и читаемый код.
Я использую это, которое использует базовое свойство BaseStream
, чтобы предоставить вам необходимую информацию о длине. Это делает вещи красивыми и простыми.
Ниже приведены три метода расширения на BinaryReader
:
Range
для указания интересующего вас подмножества данных.public static class BinaryReaderExtensions {
public static byte[] ReadBytesToEnd(this BinaryReader binaryReader) {
var length = binaryReader.BaseStream.Length - binaryReader.BaseStream.Position;
return binaryReader.ReadBytes((int)length);
}
public static byte[] ReadAllBytes(this BinaryReader binaryReader) {
binaryReader.BaseStream.Position = 0;
return binaryReader.ReadBytes((int)binaryReader.BaseStream.Length);
}
public static byte[] ReadBytes(this BinaryReader binaryReader, Range range) {
var (offset, length) = range.GetOffsetAndLength((int)binaryReader.BaseStream.Length);
binaryReader.BaseStream.Position = offset;
return binaryReader.ReadBytes(length);
}
}
Использование их тогда тривиально и понятно...
// 1 - Reads everything in as a byte array
var rawBytes = myBinaryReader.ReadAllBytes();
// 2 - Reads a string, then reads the remaining data as a byte array
var someString = myBinaryReader.ReadString();
var rawBytes = myBinaryReader.ReadBytesToEnd();
// 3 - Uses a range to read the last 44 bytes
var rawBytes = myBinaryReader.ReadBytes(^44..);
Возникла та же проблема.
Сначала получите размер файла с помощью FileInfo.Length.
Затем создайте массив байтов и установите для него значение BinaryReader.ReadBytes(FileInfo.Length). например
var size = new FileInfo(yourImagePath).Length;
byte[] allBytes = yourReader.ReadBytes(System.Convert.ToInt32(size));