Atunci când procesați loturi mari de foi de calcul Excel într-un flux automatizat, rareori doriți să încărcați întregul document în memorie doar pentru a afla ce este. Adesea, metadatele încorporate în fișier (autorul, titlul, data creării și proprietățile personalizate) sunt suficiente pentru a direcționa, indexa sau respinge documentul. În lumea Microsoft Office, aceste metadate sunt cunoscute sub numele de Document Summary Information (Informații de sumar ale documentului).
Extragerea acestor informații nativ în Delphi fără a vă baza pe automatizarea OLE (care necesită ca Excel să fie instalat pe mașina gazdă) necesită parsarea directă a structurii fișierului de bază. În acest articol, vom analiza modul în care funcționează sumarele de documente în fișierele Excel și cum să le extragem eficient utilizând parsarea directă a fluxurilor.
Înțelegerea fluxurilor de metadate Excel
Din punct de vedere istoric, fișierele Excel mai vechi (.xls) sunt stocate în formate OLE Compound Document, acționând efectiv ca niște mini-sisteme de fișiere care conțin fluxuri și zone de stocare. Metadatele sunt găzduite în două fluxuri specifice:
SummaryInformation: Conține proprietăți standard precum Title, Subject, Author, Keywords și Revision Number.DocumentSummaryInformation: Conține proprietăți extinse, cum ar fi Company, Manager și proprietăți personalizate definite de utilizator.
Fișierele Excel moderne (.xlsx) utilizează formatul Office Open XML (OOXML), care este o structură XML arhivată tip ZIP. Metadatele aici se află în docProps/core.xml, docProps/app.xml și docProps/custom.xml. O componentă robustă de parsare Delphi trebuie să gestioneze impecabil ambele structuri interne, expunând în același timp un API unificat dezvoltatorului.
Parsarea documentelor compuse OLE în Delphi
Pentru a citi informațiile de sumar dintr-un fișier `.xls` moștenit fără instrumente de la terți, trebuie să parsați stocarea structurată OLE (OLE Structured Storage). Microsoft expune acest lucru prin interfața COM IPropertySetStorage. Iată o implementare Delphi de bază care evită pornirea 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;
Extragerea programatică cu HotXLS
Deși API-ul Windows COM funcționează pentru fișierele `.xls`, nu funcționează pentru fișierele moderne `.xlsx` (care sunt arhive ZIP). Mai mult, utilizarea API-ului COM pe mai multe platforme (de exemplu, pe Linux sau macOS prin FireMonkey) este imposibilă. Actualizările recente ale componentei HotXLS au introdus unități dedicate (de exemplu, lxXlsSummary) pentru a izola și a optimiza citirea acestor fluxuri de sumar în ambele formate, complet nativ în cod Delphi.
Un exemplu multiplatformă
Utilizând interfețele XlsReadDocumentSummaryInformation și XlsReadSummaryInformation, puteți prelua rapid metadatele tip șir din ambele formate, `.xls` și `.xlsx`, fără să vă faceți griji cu privire la arhitectura sistemului de fișiere subiacent.
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;
De ce contează extragerea dedicată a sumarului
Beneficiul principal al acestei abordări este performanța și siguranța memoriei. Evitând instanțierea întregului DOM (Document Object Model) al registrului de lucru și parsând doar docProps/core.xml sau fluxurile de proprietăți OLE, amprenta aplicației dumneavoastră rămâne incredibil de mică. Dacă indexați 10.000 de fișiere Excel într-o rețea partajată, încercarea de a parsa complet fiecare fișier vă va epuiza memoria și va dura ore întregi. Extragerea dedicată a sumarului finalizează aceeași sarcină în câteva secunde.
Mai mult, citirea nativă a fluxurilor asigură faptul că aplicația dumneavoastră poate rula ca un serviciu de fundal sau pe un server Linux fără interfață grafică (headless), fără a apela vreodată Excel.exe, o cerință critică pentru arhitecturile scalabile moderne.
Notă: Instrumente cuprinzătoare pentru parsarea Excel și extragerea metadatelor sunt disponibile în HotXLS VCL Component.