Technischer Artikel

Metadata-Only und selektives XLSX-Laden mit HotXLS

HotXLS kann eine XLSX-Arbeitsmappe öffnen und gar keine Arbeitsblatt-Zellen parsen. TXLSXWorkbook.MetadataOnly liest Arbeitsmappen-Eigenschaften, definierte Namen, Blattnamen und Sichtbarkeits-Zustände, Styles, Theme, Verbindungen und externe Links und hält dann vor dem Zellen-XML an. Für einen Scanner, der wissen muss, was in einem Verzeichnis von Arbeitsmappen liegt, ist das der Unterschied zwischen Minuten und Sekunden

Drei verwandte Schalter runden das Bild ab: SelectedSheets parst Zellen für eine benannte Teilmenge, LoadSheet materialisiert ein übersprungenes Blatt später aus dem Original-Archiv, und PreserveRawParts kopiert die komprimierten Bytes unveränderter Parts beim Speichern direkt hindurch. Zusammen verwendet verwandeln sie „eine Arbeitsmappe öffnen" aus einem Alles-oder-Nichts-Vorgang in etwas, das man eingrenzen kann

Was lässt sich lernen, ohne eine einzige Zelle zu parsen?

Mehr, als die meisten Discovery-Aufgaben brauchen. Mit MetadataOnly vor Open gesetzt, kommt die Arbeitsmappe zurück und trägt ihre Blattnamen und Sichtbarkeits-Zustände, ihre definierten Namen, ihre Dokument-Eigenschaften, ihre Styles und Theme, ihre externen Links und ihre Verbindungen. Die Blätter liegen als Objekte mit null Zellen vor

Genau das ist die Information, auf der ein Katalog, eine Prüfung oder eine Routing-Entscheidung läuft. Welche Arbeitsmappen definieren einen Namen TaxRate? Welche haben ausgeblendete Blätter? Welche verlinken auf einen Server, der stillgelegt wurde? Das vollständige Laden jeder Datei zu beantworten ist der Weg, wie ein nächtlicher Auftrag zu einem Auftrag über die ganze Nacht wird

var
  Workbook: TXLSXWorkbook;
  I: Integer;
begin
  Workbook := TXLSXWorkbook.Create(nil);
  try
    Workbook.MetadataOnly := True;      // set before Open
    Workbook.Open(FileName);
    for I := 1 to Workbook.Sheets.Count do      // Sheets[] is 1-based
      if not Workbook.Sheets[I].Visible then
        Report.Add(FileName + ': hidden sheet ' +
          Workbook.Sheets[I].Name);
  finally
    Workbook.Free;
  end;
end;

Zwei Blätter von vierzig laden

SelectedSheets ist eine TStringList von Blattnamen. Ist sie nicht leer, parst Open das Zellen-XML nur für die Blätter, die sie nennt; jedes andere Blatt behält seinen korrekten Namen und Sichtbarkeits-Zustand und hält keine Zellen. Eine leere Liste bedeutet das bisherige Verhalten, also alles zu laden

Die Wechselwirkung mit MetadataOnly sollte man offen aussprechen, denn wer es verkehrt herum anwendet, erhält eine rätselhafte leere Arbeitsmappe: MetadataOnly = True setzt die Auswahl außer Kraft und überspringt alle Blätter. Das eine oder das andere verwenden. Discovery verwendet Metadata-Only; gezielte Arbeit eine Auswahl

Workbook.SelectedSheets.Add('Summary');
Workbook.SelectedSheets.Add('Q3 Detail');
Workbook.Open('consolidated-2026.xlsx');
// Later, when the user opens a tab you skipped.
// LoadSheet takes the 0-based position and needs the source file,
// so it does not work on a workbook opened from a stream
if Workbook.LoadSheet(ZeroBasedPosition) then
  Grid.Refresh;

LoadSheet(Index) materialisiert ein übersprungenes Blatt bei Bedarf aus dem Original-Archiv, was dieses Muster in einer interaktiven Anwendung nutzbar macht statt nur in einem Batch. Mit dem Blatt öffnen, das der Nutzer gerade ansieht, die anderen laden, wenn er klickt. Das Archiv bleibt genau deshalb geöffnet, also die Arbeitsmappe am Leben lassen, solange der Nutzer nach einem weiteren Blatt fragen könnte

Warum verändert ein Roundtrip Parts, die man nie angefasst hat?

Weil ein naives Speichern alles neu erzeugt. Theme dekomprimieren, ein Objekt-Modell aufbauen, es wieder serialisieren, neu komprimieren — und nun weichen die Bytes ab, obwohl sich am Theme nichts geändert hat. Für VBA-Projekte und Pivot-Caches ist das schlimmer als Verschwendung, denn diese Parts tragen Struktur, die das Objekt-Modell nicht vollständig repräsentiert

PreserveRawParts antwortet darauf, indem es die komprimierte Repräsentation unveränderter Parts während SaveAs direkt aus dem Quell-Archiv kopiert. Theme, VBA-Projekt, Pivot-Tabellen und Pivot-Caches wandern als Bytes herüber, wenn sie nicht verändert wurden. Keine Dekomprimierung, keine Rekomprimierung, kein Risiko, bei einem Serialisierungs-Roundtrip etwas zu verlieren

Der Preis ist eine Einschränkung, die man ohnehin schon hatte: Das Quell-Archiv muss zur Speicherzeit noch verfügbar sein. Liest der eigene Workflow eine Datei in den Speicher, schließt sie und speichert eine Stunde später, hat der Raw-Copy-Pfad nichts zum Kopieren. Die Quelle über die Lebensdauer der Arbeitsmappe erreichbar halten, was dieselbe Anforderung ist, die LoadSheet stellt

Eine Discovery-Pipeline, die mit Absicht erneut öffnet

Das Muster, das im Produktivbetrieb funktioniert, hat zwei Durchläufe und keine Cleverness. Durchlauf eins öffnet Metadata-Only und entscheidet. Durchlauf zwei öffnet die Dateien, auf die es ankommt, mit einer Blatt-Auswahl erneut und erledigt die Arbeit. Erneut zu öffnen wirkt verschwenderisch, bis man zählt, was Durchlauf eins vermieden hat: Das zweite Öffnen ist das einzige, das Zellen parst, und es parst nur die Blätter, die Durchlauf eins ausgewählt hat

// Pass 1: discovery
Workbook.MetadataOnly := True;
Workbook.Open(FileName);
Wanted := SheetsMatching(Workbook, 'Invoice');
Workbook.Free;

// Pass 2: targeted load
Workbook := TXLSXWorkbook.Create(nil);
Workbook.SelectedSheets.AddStrings(Wanted);
Workbook.Open(FileName);

Man sollte nicht versuchen, eine Metadata-Only-Arbeitsmappe nach dem Open durch das Löschen des Flags vor Ort zu befördern. Das Flag wird während des Öffnens gelesen; es danach zu löschen, ändert nichts an einer Arbeitsmappe, deren Zellen-XML nie besucht wurde

Wo das bei den übrigen Hebeln für große Dateien hingehört

Selektives Laden reduziert, was geparst wird. Es reduziert nicht, was ein Blatt kostet, sobald es geladen ist, und es hilft nicht, wenn man tatsächlich jede Zelle jedes Blatts braucht. Für diesen Fall liegt die relevante Arbeit auf der Speicher-Seite, beschrieben in den Hinweisen zur Row-Block-Zellen-Speicherung und zu Interval-Style-Overlays, und auf der Parse-Seite in parallelem XLSX-Parsing und der Speicher-Allokator. Wenn die Aufgabe ein reiner Scan ohne jede Bearbeitung ist, überspringt der Streaming-Direct-Reader das Objekt-Modell vollständig und wird jede Ladestrategie schlagen, die eines aufbaut

HotXLS öffnet XLS- und XLSX-Dateien aus nativem Delphi- und C++Builder-Code ohne Excel-Abhängigkeit, sodass ein serverseitiger Discovery-Auftrag mit nichts läuft, was über die eigene Executable hinaus installiert ist — siehe die HotXLS-Spreadsheet-Komponenten-Seite für die unterstützten Formate und die Lizenzierung