Při zpracování velkých dávek excelových tabulek v automatizovaném procesu jen zřídka chcete načíst celý dokument do paměti jen proto, abyste zjistili, o co jde. Často jsou metadata vložená do souboru, jako je autor, název, datum vytvoření a vlastní vlastnosti, dostačující k nasměrování, indexaci nebo odmítnutí dokumentu. Ve světě Microsoft Office jsou tato metadata známá jako souhrnné informace o dokumentu (Document Summary Information).
Nativní extrakce těchto informací v Delphi bez spoléhání na automatizaci OLE (která vyžaduje instalaci Excelu na hostitelském počítači) vyžaduje přímou analýzu základní struktury souboru. V tomto článku se podíváme na to, jak fungují souhrny dokumentů v souborech Excelu a jak je efektivně extrahovat pomocí analýzy nezpracovaných (raw) streamů.
Porozumění streamům metadat aplikace Excel
Historicky jsou starší soubory aplikace Excel (.xls) uloženy ve formátech OLE Compound Document, které efektivně fungují jako mini souborové systémy obsahující streamy a úložiště. Metadata jsou uložena ve dvou specifických streamech:
SummaryInformation: Obsahuje standardní vlastnosti jako název, předmět, autor, klíčová slova a číslo revize.DocumentSummaryInformation: Obsahuje rozšířené vlastnosti, jako je společnost, manažer a vlastní uživatelsky definované vlastnosti.
Moderní soubory aplikace Excel (.xlsx) používají formát Office Open XML (OOXML), což je komprimovaná (zipped) struktura XML. Metadata se zde nacházejí v docProps/core.xml, docProps/app.xml a docProps/custom.xml. Robustní komponenta pro analýzu v Delphi musí bez problémů zvládnout obě vnitřní struktury a zároveň vývojáři poskytnout jednotné rozhraní API.
Analýza dokumentů OLE Compound v Delphi
Pro čtení SummaryInformation ze staršího souboru `.xls` bez nástrojů třetích stran musíte analyzovat strukturované úložiště OLE. Společnost Microsoft k tomu nabízí přístup prostřednictvím rozhraní COM IPropertySetStorage. Zde je čistá implementace v Delphi, která se vyhne spuštění aplikace Excel:
uses
System.SysUtils, System.Win.ComObj, Winapi.ActiveX, Winapi.Windows;
procedure ExtractXlsSummaryInfo(const FileName: string);
var
Stg: IStorage;
PropSetStg: IPropertySetStorage;
PropStg: IPropertyStorage;
PropSpec: TPropSpec;
PropVariant: TPropVariant;
Hr: HRESULT;
begin
// Open the OLE Compound Document
Hr := StgOpenStorage(PWideChar(WideString(FileName)), nil,
STGM_READ or STGM_SHARE_DENY_WRITE, nil, 0, Stg);
if Failed(Hr) then
raise Exception.Create('Failed to open OLE storage. File may not be a valid .xls document.');
// Query for the property set storage interface
if Stg.QueryInterface(IPropertySetStorage, PropSetStg) = S_OK then
begin
// Open the SummaryInformation stream (FMTID_SummaryInformation)
Hr := PropSetStg.Open(FMTID_SummaryInformation, STGM_READ or STGM_SHARE_EXCLUSIVE, PropStg);
if Succeeded(Hr) then
begin
// Read the Author property (PIDSI_AUTHOR = 4)
PropSpec.ulKind := PRSPEC_PROPID;
PropSpec.propid := PIDSI_AUTHOR;
if PropStg.ReadMultiple(1, @PropSpec, @PropVariant) = S_OK then
begin
if PropVariant.vt = VT_LPSTR then
Writeln('Author: ', string(AnsiString(PropVariant.pszVal)));
PropVariantClear(PropVariant);
end;
end;
end;
end;
Programová extrakce pomocí HotXLS
Přestože Windows COM API funguje pro soubory `.xls`, nefunguje pro moderní soubory `.xlsx` (což jsou archivy ZIP). Kromě toho je nemožné používat rozhraní COM API napříč platformami (např. v Linuxu nebo macOS prostřednictvím FireMonkey). Nedávné aktualizace komponenty HotXLS přinesly vyhrazené jednotky (např. lxXlsSummary) k izolaci a optimalizaci čtení těchto souhrnných streamů v obou formátech, a to zcela nativně v kódu Delphi.
Příklad nezávislý na platformě
Pomocí rozhraní XlsReadDocumentSummaryInformation a XlsReadSummaryInformation můžete rychle získat řetězce metadat ze souborů `.xls` i `.xlsx`, aniž byste se museli starat o základní architekturu souborového systému.
uses
lxXlsSummary;
var
Summary: TXlsSummaryInfo;
ExtendedInfo: TXlsDocumentSummaryInfo;
begin
// Extract standard summary from an OOXML format seamlessly
Summary := XlsReadSummaryInformation('C:\Data\FinancialReport.xlsx');
try
Writeln('Title: ', Summary.Title);
Writeln('Author: ', Summary.Author);
Writeln('Creation Date: ', DateTimeToStr(Summary.CreateTime));
finally
Summary.Free;
end;
// Extract extended document summary
ExtendedInfo := XlsReadDocumentSummaryInformation('C:\Data\FinancialReport.xlsx');
try
Writeln('Company: ', ExtendedInfo.Company);
Writeln('Manager: ', ExtendedInfo.Manager);
finally
ExtendedInfo.Free;
end;
end;
Proč záleží na vyhrazené extrakci souhrnů
Hlavní výhodou tohoto přístupu je výkon a bezpečnost paměti. Tím, že se vyhnete instanciaci plného DOM (Document Object Model) sešitu a analyzujete pouze docProps/core.xml nebo streamy vlastností OLE, zůstane paměťová stopa vaší aplikace neuvěřitelně malá. Pokud indexujete 10 000 souborů Excelu na síťové sdílené složce, pokus o úplnou analýzu každého z nich zahltí vaši paměť a potrvá hodiny. Vyhrazená extrakce souhrnů dokončí stejný úkol v řádu sekund.
Kromě toho nativní čtení streamů zajišťuje, že vaše aplikace může běžet jako služba na pozadí nebo na serveru Linux bez grafického rozhraní (headless), aniž by kdy vyvolala soubor Excel.exe, což je kritický požadavek pro moderní škálovatelné architektury.
Poznámka: Komplexní nástroje pro analýzu Excelu a extrakci metadat jsou k dispozici v komponentě HotXLS VCL Component.