はじめに

ビジネスで大量の請求書、法的文書、またはメールエクスポートが圧縮された ZIP や RAR ファイルとして届く場合、従来の手法はそれらをディスクへ解凍し、個々のリーダーでファイルを開き、最後に一時ファイルを削除するというものです。この往復処理は高コストな I/O を生み、クリーンアップを複雑にし、ネストされたアーカイブの取り扱いを悪夢のようにします。

GroupDocs.Parser for .NET はこれらの課題を解消します。アーカイブを直接開き、すべてのエントリを列挙し、生テキスト(およびメタデータ)を完全にメモリ上で抽出できます。本記事では以下を学びます。

  • Parser NuGet パッケージをインストールする。
  • フラットなアーカイブからテキストを一度のパスで取得する。
  • ネストされた ZIP/RAR ファイルを再帰的に走査する。
  • 堅牢な処理のためのベストプラクティス設定を適用する。

メモリ内アーカイブ解析が重要な理由

  • 一時ファイルゼロ – ディスクが散らからず、残りファイルもない。
  • 高速 – 各エントリの余分な読み書きサイクルを回避する。
  • スケーラビリティ – ファイルシステムが利用できない大規模アーカイブやクラウドストリームを処理できる。

前提条件

  • .NET 6.0 以降。
  • GroupDocs.Parser for .NET(最新バージョン) – 無料評価には 一時ライセンス をご参照ください。
  • サポートされているドキュメント(PDF、DOCX、TXT など)を含む ZIP または RAR アーカイブ。

インストール

dotnet add package GroupDocs.Parser

必要な名前空間を追加します:

using GroupDocs.Parser;
using GroupDocs.Parser.Data;
using System.Collections.Generic;
using System.IO;

ステップ 1 – アーカイブを開く

最初のステップは、アーカイブ ファイルを指す Parser インスタンスを作成することです。GetContainer() はアーカイブ内のエントリごとに 1 つずつ 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 – 各エントリを処理する

ExtractDataFromAttachmentsContainerItem リストを走査し、基本的なメタデータを出力、ネストされたアーカイブを検出し、通常ドキュメントからテキストを抽出します。このメソッドは完全に再利用可能で、トップレベルのアーカイブに対して一度呼び出し、見つかった任意のネストアーカイブに対して再度呼び出します。

/// <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 を捕捉することで、1つの不正ファイルが全体の実行を中止しません。

ステップ 3 – すべてをまとめる

以下は上記 2 つのスニペットを組み合わせた最小限のコピー&ペースト可能なプログラムです。インストール、オープン、処理、レポートというエンドツーエンドのフローを示しています。

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 アーカイブ内のすべてのドキュメントを、どれほど深くネストされていても、クリーンでメモリ内の方法で読み取る手段を提供します。数行のコードで複雑な unzip+parse パイプラインを置き換え、I/O オーバーヘッドを削減し、信頼性の高い文書取り込みサービスを構築できます。

次のステップ

  • 文書比較 または メタデータ抽出 機能を探る。
  • 同じ API でアーカイブ内ファイルから画像を抽出する方法を学ぶ。
  • 抽出したテキストを検索インデックスや AI パイプラインに統合する。

追加リソース