技術記事

HotXLSでメタデータのみと選択的シート読み込みを行う方法

HotXLSはXLSXブックを開き、ワークシートのセルを1つもパースしないことができる。TXLSXWorkbook.MetadataOnlyはブックプロパティ、定義名、シート名と可視状態、スタイル、テーマ、コネクション、外部リンクを読み、セルXMLの前で止まる。ワークブックのディレクトリの中身を知る必要があるスキャナにとって、これは分と秒の差になる

3つの関連スイッチが全体を完成させる。SelectedSheetsは名指しされたサブセットのセルだけをパースし、LoadSheetは後から元のアーカイブからスキップされたシートを実体化し、PreserveRawPartsは変更されていないパートの圧縮バイトを保存時にそのまま通す。これらを組み合わせれば、「ブックを開く」という1つのオールオアナッシング操作を、スコープを絞れるものに変えられる

1つのセルもパースせずに何を知れるのか

ほとんどの発見タスクが必要とする以上のものだ。Openの前にMetadataOnlyを設定しておくと、ブックはシート名と可視状態、定義名、ドキュメントプロパティ、スタイルとテーマ、外部リンク、コネクションを保持して戻ってくる。シートは、セルゼロのオブジェクトとして存在する

それはまさに、カタログ、監査、ルーティングの判断が依る情報だ。どのブックがTaxRateという名前を定義しているか。どれが非表示シートを持つか。どれがすでに廃止されたサーバーへリンクしているか。すべてのファイルを完全に読み込んでこれらに答えるのが、夜のジョブを一晩中走るジョブにしてしまう方法だ

HotXLS MetadataOnly は Delphi XLSX アーカイブ内のブックプロパティ、シート名、スタイル、リンクを読み、その後ワークシートセル XML の前に停止
MetadataOnly はアーカイブのすべての構造パートを読み、ワークシートのセル XML の手前で止まります。Delphi ワークブックは、シート名、可視性、定義名、スタイルを持ち、セルはゼロで戻ります
var
  Workbook: TXLSXWorkbook;
  I: Integer;
begin
  Workbook := TXLSXWorkbook.Create;
  try
    Workbook.MetadataOnly := True;      // Openの前に設定する
    Workbook.Open(FileName);
    for I := 1 to Workbook.Sheets.Count do      // Sheets[]は1ベース
      if not Workbook.Sheets[I].Visible then
        Report.Add(FileName + ': hidden sheet ' +
          Workbook.Sheets[I].Name);
  finally
    Workbook.Free;
  end;
end;

40のうち2つのシートだけを読み込む

SelectedSheetsはシート名のTStringListだ。空でないとき、Openは名指しされたシートのセルXMLだけをパースし、それ以外の各シートは正しい名前と可視状態を保ちつつセルを保持しない。空のリストは、すべてを読み込むという以前の挙動を意味する

MetadataOnlyとの相互作用は、後ろ向きに取ると当惑する空のブックを生むので、はっきりと述べておく価値がある。MetadataOnly = Trueは選択を上書きし、すべてのシートをスキップする。どちらか一方を使うこと。発見はメタデータのみを使い、的を絞った作業は選択を使う

HotXLS SelectedSheets は Delphi で 40 シート中の 2 つの名前付きシートのセルを解析し、LoadSheet はスキップされたシートをまだ開いているアーカイブから実体化
SelectedSheets は指定シートのセル XML だけを解析し、残りは名前と可視性を保つ空のスタブのままにします。LoadSheet は後からスタブを実体化できます。ソースアーカイブがまだ開いている場合に限ります
Workbook.SelectedSheets.Add('Summary');
Workbook.SelectedSheets.Add('Q3 Detail');
Workbook.Open('consolidated-2026.xlsx');
// 後で、ユーザーがスキップしたタブを開いたとき。
// LoadSheetは0ベースの位置を取り、ソースファイルを必要とするため、
// ストリームから開かれたワークブックでは動作しない
if Workbook.LoadSheet(ZeroBasedPosition) then
  Grid.Refresh;

LoadSheet(Index)はスキップされたシートを元のアーカイブからオンデマンドで実体化する。これこそ、このパターンをバッチだけでなくインタラクティブなアプリでも使えるものにする。ユーザーが見ているシートを開き、クリックされたときにほかを読み込む。アーカイブはまさにそのために開かれたままである。だからユーザーが別のシートを求める可能性がある限り、ブックを生かしておくこと

なぜラウンドトリップは触れてもいないパートを変えるのか

素朴な保存がすべてを再生成するからだ。テーマを展開し、オブジェクトモデルを構築し、シリアライズして戻し、再圧縮する。するとテーマについて何も変わっていないのにバイトが異なる。VBAプロジェクトやピボットキャッシュでは、それは無駄である以上に悪い。それらのパートはオブジェクトモデルが完全には表現しない構造を運ぶからだ

PreserveRawPartsは、SaveAsの間に変更されていないパートの圧縮表現をソースアーカイブから直接コピーすることでこれに答える。テーマ、VBAプロジェクト、ピボットテーブル、ピボットキャッシュは、変更されなかったときバイトとしてそのまま渡される。展開も再圧縮もなく、シリアライズのラウンドトリップで何かを失うリスクもない

コストは、あなたがすでに持っていた制約だ。ソースアーカイブは保存時にも利用可能でなければならない。ワークフローがファイルをメモリに読み込み、閉じ、1時間後に保存するなら、raw コピーのパスはコピー元を持たない。ブックのライフタイムの間ソースを到達可能に保つこと。これはLoadSheetが課すのと同じ要件だ

意図的に2度開く発見パイプライン

本番で働くパターンは、2つのパスを持ち、小細工を持たない。パス1はメタデータのみで開いて決定する。パス2は、意味のあるファイルを選択されたシートとともに開き直し、作業を行う。開き直しは無駄に見えるが、パス1が回避したものを数えれば納得できる。2回目のオープンだけがセルをパースし、しかもパス1が選んだシートだけをパースするのだ

Delphi における 2 パス HotXLS ディスカバリーパイプライン。メタデータのみのパスがどのブックとシートが重要かを決め、その後ターゲットを絞ったパスが選択されたシートのみ解析
第 1 パスはディレクトリをメタデータのみで走査し、どのファイルとシートが重要かを決めます。第 2 パスは一致したものをシート選択付きで開き直します。セル XML を解析するのは第 2 のオープンだけです
// パス1: 発見
Workbook.MetadataOnly := True;
Workbook.Open(FileName);
Wanted := SheetsMatching(Workbook, 'Invoice');
Workbook.Free;

// パス2: 的を絞った読み込み
Workbook := TXLSXWorkbook.Create;
Workbook.SelectedSheets.AddStrings(Wanted);
Workbook.Open(FileName);

Openの後にフラグをクリアしてメタデータのみのブックをインプレースで昇格しようとしないこと。フラグはオープン中に読まれる。後にクリアしても、セルXMLが訪問されなかったブックについて何も変えない

ほかの大ファイル向けレバーとの関係

選択的読み込みはパースするものを減らす。一度読み込まれたシートのコストは減らさないし、本当にすべてのシートのすべてのセルが必要な場合も助けない。そのケースでは、関連する作業はストレージ側にあり、行ブロックのセルストレージと区間スタイルオーバーレイのノートと、パース側の並列XLSXパースとメモリアロケータで説明されている。編集をまったく伴わない純粋なスキャンがタスクなら、ストリーミング直接リーダーはオブジェクトモデルを完全にスキップし、オブジェクトモデルを構築するあらゆる読み込み戦略を上回る

HotXLSはネイティブのDelphiとC++BuilderコードからXLSとXLSXを開き、Excelへの依存を持たない。だからサーバーサイドの発見ジョブは、自社の実行可能ファイル以外には何もインストールせずに走る。サポートされるフォーマットとライセンスについてはHotXLSスプレッドシートコンポーネントページを参照のこと