Код, который вы показываете, считывает все содержимое файла 500 МБ в непрерывную область в памяти.
Не удивительно, что вы получаете состояние нехватки памяти.
Решение - «не делай этого».
Что вы действительно пытаетесь сделать?
Если вы хотите полностью прочитать файл, это намного проще, чем метод ReadFully, который вы используете. Попробуйте это:
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[fs.Length];
int bytesRead = fs.Read(buffer, 0, buffer.Length);
// buffer now contains the entire contents of the file
}
Но ... использование этого кода не решит вашу проблему. Это может работать для файла 500 МБ. Это не будет работать для файла 750 МБ или файла 1 ГБ. В какой-то момент вы достигнете предела памяти в вашей системе и у вас будет та же ошибка нехватки памяти, с которой вы начали.
Проблема в том, что вы пытаетесь одновременно удерживать все содержимое файла в памяти. Обычно это не нужно и обречено на провал, поскольку файлы увеличиваются в размере. Это не проблема, когда размер файла составляет 16 КБ. На 500мб это неправильный подход.
Вот почему я несколько раз спрашивал: что вы действительно пытаетесь сделать ?
Звучит так, будто вы хотите отправить содержимое файла в поток ответов ASPNET. Это вопрос. Не "как прочитать файл 500 МБ в память?" Но "как отправить большой файл в поток ответов ASPNET?"
Для этого, опять же, это довольно просто.
// emit the contents of a file into the ASPNET Response stream
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
Response.BufferOutput= false; // to prevent buffering
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
{
Response.OutputStream.Write(buffer, 0, bytesRead);
}
}
То, что он делает, - это итеративное чтение фрагмента из файла и запись этого фрагмента в поток ответа, пока в файле больше нечего читать. Это то, что подразумевается под «потоковым вводом-выводом». Данные проходят через вашу логику, но никогда не хранятся все в одном месте, так же как поток воды проходит через шлюз. В этом примере никогда не бывает более 1k файловых данных в памяти за один раз (ну, в любом случае, не удерживается вашим кодом приложения. В стеке находятся другие буферы ввода-вывода ниже).
Это обычная схема потокового ввода-вывода. Изучи это, используй это.
Единственный прием при перекачке данных в ASPNET Response.OutputStream - установить BufferOutput = false
. По умолчанию ASPNET пытается буферизовать свой вывод. В этом случае (файл 500 МБ) буферизация - плохая идея. Если для свойства BufferOutput
указано значение false, ASPNET не попытается буферизовать все данные файла перед отправкой первого байта. Используйте это, когда вы знаете, что файл, который вы отправляете, очень большой. Данные все равно будут отправлены в браузер правильно.
И даже это не полное решение. Вам нужно будет установить заголовки ответа и так далее. Я думаю, вы знаете об этом, хотя.