При помощи чего лучше сделать экспорт/импорт огромного количества файлов в один файл или из него (C#)?
У меня есть отдельные папки в каждой из которых хранится файл с метаданными и огромное количество изображений (могут быть сотни тысяч). Общий размер всех папок может составлять гигабайты, а то и десятки гигабайт.
По выбору пользователя отдельные папки или все надо сохранить в один файл.
Я пробовал сохранять в zip архив без сжатия при помощи библиотеки DotNetZip, но даже с опцией использования x64 реализации обработка всех файлов занимает продолжительное время и в конце может вывалиться с ошибкой.
Вопрос в том, может есть какое-то готовое решение для C# (net framework 4.5), с помощью которого я мог бы сделать такой экспорт/импорт без изобретений лишних велосипедов? Обязательно чтобы была возможность получения прогресса экспорта/импорта. И перед импортом надо вытащить из этого архивного файла список того, что там есть для выбора нужного (на данный момент в zip архив добавляется дополнительный файл, где этот список записан).
public void Zip(string path)
{
// добавить сборку System.IO.Compression.FileSystem
// добавить сборку System.IO.Compression
var file = ZipFile.Open(path, ZipArchiveMode.Create);
// выбираете что там и как повторяете до упора
var newFile = "";
file.CreateEntryFromFile(newFile, "NewEntry.txt",CompressionLevel.NoCompression);
}
Добавляет ли метод CreateEntryFromFile информацию о новом файле в какой-нибудь внутренний список файлов в архиве? Если так, то может съесть всю память.
Для чтения архива используется метод ZipFile.OpenRead(zipPath) и свойство Entries. Я правильно понимаю что это свойство считывает весь список файлов в память?
В принципе можно при архивировании создавать параллельно временный файл со списком всех изображений в конкретной папке. И в начале доставать файл (через метод GetEntry) со списком папок и потом файлы со списком файлов отдельных выбранных папок распаковать во временную папку и последовательно читать, не загружая память и не считывая список вообще всего, что есть в архиве.
Если этот подход не ест память, то он мне однозначно подходит.
Сделал проверку такого создания zip архива. В общем архив без использования лишней памяти создается, тут проблем нет.
А вот открытие архива всё равно считывает всю таблицу файлов zip архива в память :( При 90к файлов это в общем-то не страшно, а вот при миллионе уже может занять существенное пространство в памяти.
Есть ли какой-то способ извлечь конкретный файл из zip архива не читая всю таблицу в память?
// открывает поток, не файл!!!
using (ZipArchive archive = ZipFile.OpenRead(zipPath))
{
// перебирает заголовки. Не файлы
foreach (ZipArchiveEntry entry in archive.Entries)
{
// понимаем что это наш клиент, условие может быть любое
if (entry.FullName.EndsWith(".txt", StringComparison.OrdinalIgnoreCase))
{
// Gets the full path to ensure that relative segments are removed.
string destinationPath = Path.GetFullPath(Path.Combine(extractPath, entry.FullName));
// Ordinal match is safest, case-sensitive volumes can be mounted within volumes that
// are case-insensitive.
if (destinationPath.StartsWith(extractPath, StringComparison.Ordinal))
entry.ExtractToFile(destinationPath); // только тут начинаем извлекать, причем память используется минимально это поток
}
}
}
Владимир Коротенко, вопрос не в объеме файлов, а в их количестве. У меня могут быть сотни тысяч файлы в архиве. Поэтому в списке Entries будет объект на каждый файл. В принципе сложно забить память, но лучше если решение будет по возможности потреблять как можно меньше памяти.
Склоняюсь к тому, что делать промежуточные архивы. Например по 10к файлов и записывать их в основной архивный файл.
Евгений, Я еще раз говорю. Это поток!
Вы по нему итерируете и память выделяется только на одну ноду, если конешно не запросите весь лист (не делайте так)
Используйте фильтры, отложенную загрузку, есть много техник.
Владимир Коротенко, я ставил точку останова и делал профилирование памяти. Сразу после первой строчки весь список Entries уже заполнен сущностями для каждого файла в архиве. И все это сидит в памяти.
И тип свойства ReadOnlyCollection, а не IEnumerable.
Владимир Коротенко, Где-то 40 мегабайт на 90к. В одной папке (мне скинули пример) есть миллион с лишним файлов. То есть это уже серьезный размер будет. Стоит учитывать что компьютеры клиента вовсе не топовые.