2013-03-29 1 views
1

У нас есть требование к приложению Winforms читать тысячи файлов из локальной файловой системы (или сетевого расположения) и хранить их в базе данных.Эффективный способ передачи многих двоичных файлов в базу данных SQL Server

Мне интересно, что было бы самым эффективным способом загрузки файлов? В целом потенциально может быть много гигабайт данных.

File.ReadAllBytes В настоящее время используется, но приложение в конечном итоге блокируется, поскольку память компьютера израсходована.

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

protected CustomFile ConvertFile(string path) 
{ 
    try 
    { 
     byte[] file = File.ReadAllBytes(path); 
     return new CustomFile { FileValue = file }; 
    } 
    catch 
    { 
     return null; 
    } 
} 

Данные затем сохраняются в базу данных (или SQL Server 2008 R2 или 2012) с использованием NHibernate как ОРМ.

+1

Какой вид базы данных? –

+0

Самый большой файл? –

+0

Можете ли вы показать нам свой код? Возможно, небольшая настройка вашего кода может быть в порядке. –

ответ

0

Если у вас есть много файлов, вы должны прочитать их один за другим.

Если у вас есть большие файлы, и база данных позволяет это, вы должны прочитать их блок за блоком в буфер и записать их по блоку в базу данных. Если вы используете File.ReadAllBytes, вы можете получить OutOfMemoryException, когда файл слишком велик, чтобы вписаться в память времени выполнения. Верхний предел меньше 2 гигабайт и даже меньше, когда память фрагментирована, когда приложение работает некоторое время.

1

Прежде всего, позвольте мне сказать, что мои знания - это pre NET 4.0, поэтому эта информация может быть устаревшей, потому что я знаю, что они собираются сделать улучшения в этой области.

Не используйте File.ReadAllBytes для чтения больших файлов (размером более 85 КБ), особенно если вы делаете это со многими файлами последовательно. Повторяю, не надо.

Используйте что-то вроде потока и BinaryReader.Read вместо этого, чтобы сохранить ваше чтение. Даже если это может показаться неэффективным, поскольку вы не будете взорвать процессор через один буфер, если вы сделаете это с помощью ReadAllBytes, он просто не будет работать, как вы обнаружили.

Причина этого в том, что ReadAllBytes читает все в байтовом массиве. Если этот массив байтов составляет> 85 КБ в памяти (есть и другие соображения, например, # элементов массива), он входит в кучу больших объектов, что отлично, НО, LOH не перемещает память и не дефрагментирует освобожденное пространство, поэтому , упрощение, это может произойти:

  • Прочитано 1GB файл, у вас есть 1GB кусок в LOH, сохраните файл. (Нет цикла GC)
  • Прочтите 1,5 Гбайт файла, вы запросите 1,5 ГБ памяти, он входит в конец LOH, но скажите, что вы получаете GC-цикл, так что 1GB-фрагмент, который вы ранее использовали, очищается, но теперь у вас есть кусок 2,5 ГБ памяти, первый 1 ГБ бесплатно.
  • Прочитано 1,6 ГБ файла, 1 ГБ свободного блока в начале не работает, поэтому распределитель идет до конца. Теперь у вас есть блок памяти объемом 4,1 ГБ.
  • Повторите.

У вас заканчивается память, но вы, конечно же, не используете ее полностью, фрагментация, вероятно, убивает вас. Кроме того, вы действительно можете столкнуться с реальной ситуацией OOM, если файл очень большой (я думаю, что пространство процесса в Windows 32 бит составляет 2 ГБ?).

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

Ссылки:

http://www.red-gate.com/products/dotnet-development/ants-memory-profiler/learning-memory-management/memory-management-fundamentals

https://www.simple-talk.com/dotnet/.net-framework/the-dangers-of-the-large-object-heap/

+0

Вы предполагаете, что база данных позволяет записывать один BLOB в несколько блоков. Полагаю, это возможно. Я никогда не видел этого, но я не парень DB. Нет необходимости в 'BinaryReader'. 'FileStream.Read' отлично работает и экономит вам создание' BinaryReader'. –

+0

При необходимости он также может читать * много * буферов, а не один. Это не защитит от больших файлов, потребляющих всю память, но это, безусловно, будет против фрагментации. (Если буферы остаются вне LOH) –

+0

Хорошо, поэтому использование File.ReadAllBytes - плохая идея, поскольку она заполняет LOH, где память не может быть легко восстановлена. Как я могу прочитать содержимое файла в массив байтов, не сталкиваясь с этой проблемой? – user1838662

Смежные вопросы