Введение
Когда вашему бизнесу необходимо обрабатывать большие партии счетов, юридических документов или экспортированных электронных писем, которые приходят в виде сжатых файлов ZIP или RAR, традиционный подход заключается в их распаковке на диск, открытии каждого файла отдельным считывателем и последующем удалении временных файлов. Такой цикл добавляет дорогие операции ввода‑вывода, усложняет очистку и делает работу с вложенными архивами настоящим кошмаром.
GroupDocs.Parser for .NET устраняет эти проблемы. Он позволяет открывать архив напрямую, перечислять каждую запись и извлекать исходный текст (и метаданные) полностью в памяти. В этой статье вы узнаете, как:
- Установить пакет Parser через NuGet.
- Извлечь текст из плоского архива за один проход.
- Рекурсивно обходить вложенные файлы ZIP/RAR.
- Применять рекомендации по настройкам для надёжной обработки.
Почему парсинг архивов в памяти имеет значение
Обработка архивов в памяти даёт вам:
- Ноль временных файлов – нет захламления диска, нет оставшихся файлов.
- Скорость – избегаете дополнительного цикла чтения/записи для каждой записи.
- Масштабируемость – обрабатывайте большие архивы или потоки из облака, где файловая система может быть недоступна.
Предпосылки
- .NET 6.0 или новее.
- GroupDocs.Parser for .NET (последняя версия) – см. temporary license для бесплатной оценки.
- Архив ZIP или RAR, содержащий поддерживаемые документы (PDF, DOCX, TXT и т.д.).
Установка
dotnet add package GroupDocs.Parser
Добавьте необходимые пространства имён:
using GroupDocs.Parser;
using GroupDocs.Parser.Data;
using System.Collections.Generic;
using System.IO;
Шаг 1 – Открытие архива
Первый шаг – создать экземпляр Parser, указывающий на файл архива. GetContainer() возвращает коллекцию объектов ContainerItem – по одному на каждую запись внутри архива.
// Path to the archive you want to scan
string archivePath = "./SampleDocs/InvoicesArchive.zip";
using (Parser parser = new Parser(archivePath))
{
// Retrieve every file (or nested archive) inside the container
IEnumerable<ContainerItem> attachments = parser.GetContainer();
if (attachments == null)
{
Console.WriteLine("Archive is empty or could not be read.");
return;
}
// Hand off the collection to a helper that extracts text/metadata
ExtractDataFromAttachments(attachments);
}
Что происходит:
- Конструктор
Parserзагружает архив без его распаковки на диск. GetContainer()лениво читает каталог архива и предоставляет вам объектыContainerItem, с которыми можно работать.
Шаг 2 – Обработка каждой записи
ExtractDataFromAttachments проходит по списку ContainerItem, выводит базовые метаданные, определяет вложенные архивы и извлекает текст из обычных документов. Метод полностью переиспользуем – вызовите его один раз для архивного уровня и снова для любого найденного вложенного архива.
/// <summary>
/// Recursively extracts metadata and plain‑text from each item in an archive.
/// </summary>
static void ExtractDataFromAttachments(IEnumerable<ContainerItem> attachments)
{
foreach (ContainerItem item in attachments)
{
// Print a quick line with file name and size (optional)
Console.WriteLine($"File: {item.FilePath} | Size: {item.Metadata.Size} bytes");
try
{
// Each ContainerItem can open its own Parser instance
using (Parser itemParser = item.OpenParser())
{
if (itemParser == null)
{
// The item is not a supported document – skip it
continue;
}
// Detect nested archives by extension (case‑insensitive)
bool isArchive = item.FilePath.EndsWith(".zip", StringComparison.OrdinalIgnoreCase) ||
item.FilePath.EndsWith(".rar", StringComparison.OrdinalIgnoreCase);
if (isArchive)
{
// Recursively process the inner archive
IEnumerable<ContainerItem>? nested = itemParser.GetContainer();
if (nested != null)
{
ExtractDataFromAttachments(nested);
}
}
else
{
// Regular document – extract its raw text
using (TextReader reader = itemParser.GetText())
{
string text = reader.ReadToEnd();
Console.WriteLine($"Extracted {text.Length} characters from {item.FilePath}");
// Here you could store `text` in a database, index it, etc.
}
}
}
}
catch (UnsupportedDocumentFormatException)
{
// The file type is not supported by GroupDocs.Parser – ignore gracefully
Console.WriteLine($"Skipping unsupported format: {item.FilePath}");
}
}
}
Ключевые моменты
- Доступ к метаданным –
item.Metadataдаёт вам имя файла, размер, дату создания и т.д., без чтения содержимого файла. - Рекурсивная обработка – тот же метод вызывает сам себя при обнаружении ещё одного ZIP/RAR, обеспечивая поддержку неограниченного уровня вложенности.
- Устойчивость к ошибкам –
UnsupportedDocumentFormatExceptionперехватывается, чтобы один плохой файл не прервал всю работу.
Шаг 3 – Сбор всех частей вместе
Ниже представлен минимальный, готовый к копированию пример программы, объединяющий два фрагмента выше. Он демонстрирует полный сквозной процесс: установка, открытие, обработка и отчёт.
using GroupDocs.Parser;
using GroupDocs.Parser.Data;
using System;
using System.Collections.Generic;
using System.IO;
class ArchiveTextExtractor
{
static void Main(string[] args)
{
string archivePath = args.Length > 0 ? args[0] : "./SampleDocs/InvoicesArchive.zip";
using (Parser parser = new Parser(archivePath))
{
IEnumerable<ContainerItem> attachments = parser.GetContainer();
if (attachments == null)
{
Console.WriteLine("No items found in the archive.");
return;
}
ExtractDataFromAttachments(attachments);
}
}
static void ExtractDataFromAttachments(IEnumerable<ContainerItem> attachments)
{
foreach (ContainerItem item in attachments)
{
Console.WriteLine($"File: {item.FilePath} | Size: {item.Metadata.Size} bytes");
try
{
using (Parser itemParser = item.OpenParser())
{
if (itemParser == null) continue;
bool isArchive = item.FilePath.EndsWith(".zip", StringComparison.OrdinalIgnoreCase) ||
item.FilePath.EndsWith(".rar", StringComparison.OrdinalIgnoreCase);
if (isArchive)
{
var nested = itemParser.GetContainer();
if (nested != null) ExtractDataFromAttachments(nested);
}
else
{
using (TextReader reader = itemParser.GetText())
{
string text = reader.ReadToEnd();
Console.WriteLine($"Extracted {text.Length} chars from {item.FilePath}");
}
}
}
}
catch (UnsupportedDocumentFormatException)
{
Console.WriteLine($"Unsupported format: {item.FilePath}");
}
}
}
}
Запустите программу, указав путь к вашему архиву:
dotnet run -- ./Data/LegalDocs.zip
Лучшие практики и советы
- Ограничьте параметры парсинга – по умолчанию Parser извлекает весь поддерживаемый контент. Если вам нужен только текст, избегайте вызова дополнительных тяжёлых методов, таких как
GetImages(). - Большие архивы – обрабатывайте элементы последовательно, как показано; не загружайте все тексты в память сразу.
- Производительность – пропускайте вложенные архивы, которые вам не нужны, проверяя расширение файла перед рекурсией.
- Обработка ошибок – всегда перехватывайте
UnsupportedDocumentFormatException; в корпоративных архивах часто встречаются бинарные файлы, которые парсер не может прочитать.
Заключение
GroupDocs.Parser for .NET предоставляет чистый, полностью основанный на памяти способ чтения каждого документа внутри ZIP или RAR архивов, независимо от глубины их вложенности. Всего несколькими строками кода вы можете заменить сложные конвейеры «распаковать + парсить», сократить накладные расходы ввода‑вывода и построить надёжные сервисы ingest‑а документов.
Следующие шаги
- Изучите функции document comparison или metadata extraction.
- Узнайте, как извлекать изображения из архивных файлов тем же API.
- Интегрируйте извлечённый текст в поисковый индекс или AI‑конвейер.