Лучший способ чтения большого файла в массив байтов в C #?

У меня есть веб-сервер, который будет читать большие двоичные файлы (несколько мегабайт) в байтовые массивы. Сервер может одновременно считывать несколько файлов (разные запросы страниц), поэтому я ищу наиболее оптимизированный способ сделать это, не слишком сильно нагружая процессор. Является ли код ниже достаточно хорошим?

public byte[] FileToByteArray(string fileName) { byte[] buff = null; FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); BinaryReader br = new BinaryReader(fs); long numBytes = new FileInfo(fileName).Length; buff = br.ReadBytes((int) numBytes); return buff; } 

Просто замените все:

 return File.ReadAllBytes(fileName); 

Однако, если вас беспокоит потребление памяти, вы не должны полностью считывать весь файл в памяти. Вы должны сделать это в кусках.

Я могу утверждать, что ответ здесь вообще «не надо». Если вам абсолютно не нужны все данные сразу, подумайте об использовании API с интерфейсом Stream (или некоторого варианта reader / iterator). Это особенно важно, когда у вас есть несколько параллельных операций (как было предложено в вопросе), чтобы минимизировать нагрузку на систему и увеличить пропускную способность.

Например, если вы передаете данные абоненту:

 Stream dest = ... using(Stream source = File.OpenRead(path)) { byte[] buffer = new byte[2048]; int bytesRead; while((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0) { dest.Write(buffer, 0, bytesRead); } } 

Я бы подумал:

 byte[] file = System.IO.File.ReadAllBytes(fileName); 

Ваш код может быть учтен для этого (вместо File.ReadAllBytes):

 public byte[] ReadAllBytes(string fileName) { byte[] buffer = null; using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read)) { buffer = new byte[fs.Length]; fs.Read(buffer, 0, (int)fs.Length); } return buffer; } 

Обратите внимание на Integer.MaxValue – ограничение размера файла, установленное методом Read. Другими словами, вы можете читать только 2 ГБ кусок сразу.

Также обратите внимание, что последним аргументом FileStream является размер буфера.

Я бы также предложил прочитать о FileStream и BufferedStream .

Как всегда, самая простая программа-образец для самого быстрого профиля будет наиболее полезной.

Также ваше основное оборудование будет иметь большое влияние на производительность. Используете ли вы серверные жесткие диски с большими кешами и RAID-карту с встроенным кешем памяти? Или вы используете стандартный диск, подключенный к порту IDE?

В зависимости от частоты операций, размера файлов и количества файлов, на которые вы смотрите, есть другие проблемы с производительностью, которые необходимо учитывать. Одна вещь, которую следует помнить, состоит в том, что каждый из ваших байтовых массивов будет выпущен во власти сборщика мусора. Если вы не кешируете какие-либо данные, вы можете создать много мусора и потерять большую часть своей производительности % Time in GC . Если куски больше 85K, вы будете выделять кучу больших объектов (LOH), для чего потребуется сбор всех поколений для освобождения (это очень дорого, и на сервере прекратится все выполнение, пока оно происходит ). Кроме того, если у вас есть тонна объектов на LOH, вы можете завершить fragmentацию LOH (LOH никогда не уплотняется), что приводит к низкой производительности и исключениям из памяти. Вы можете переработать процесс, как только попадете в определенный момент, но я не знаю, является ли это лучшей практикой.

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

Я бы сказал, что BinaryReader в порядке, но может быть реорганизован на это вместо всех этих строк кода для получения длины буфера:

 public byte[] FileToByteArray(string fileName) { byte[] fileData = null; using (FileStream fs = File.OpenRead(fileName)) { using (BinaryReader binaryReader = new BinaryReader(fs)) { fileData = binaryReader.ReadBytes((int)fs.Length); } } return fileData; } 

Должен быть лучше, чем использовать .ReadAllBytes() , так как я видел в комментариях к верхнему отклику, который включает .ReadAllBytes() что у одного из комментаторов были проблемы с файлами> 600 МБ, поскольку BinaryReader предназначен для такого рода вещей. Кроме того, включение его в оператор using гарантирует, что FileStream и BinaryReader будут закрыты и удалены.

Используйте class BufferedStream на C # для повышения производительности. Буфер представляет собой блок байтов в памяти, используемый для кэширования данных, тем самым уменьшая количество вызовов в операционной системе. Буферы улучшают производительность чтения и записи.

Для примера кода и дополнительного объяснения см. Следующее: http://msdn.microsoft.com/en-us/library/system.io.bufferedstream.aspx

Я бы рекомендовал попробовать метод Response.Flush() а затем Response.Flush() и Response.End() для обслуживания ваших больших файлов.

Если вы имеете дело с файлами выше 2 ГБ, вы обнаружите, что приведенные выше методы не работают.

Гораздо проще просто передать stream на MD5 и разрешить вам вырезать файл для вас:

 private byte[] computeFileHash(string filename) { MD5 md5 = MD5.Create(); using (FileStream fs = new FileStream(filename, FileMode.Open)) { byte[] hash = md5.ComputeHash(fs); return hash; } } 
Давайте будем гением компьютера.