Apdorojant dideles „Excel“ skaičiuoklių partijas automatizuotame procese, retai kada norima įkelti visą dokumentą į atmintį vien tam, kad sužinotumėte, kas tai yra. Dažnai faile įterptų metaduomenų (autoriaus, pavadinimo, sukūrimo datos ir pasirinktinių savybių) pakanka norint nukreipti, indeksuoti ar atmesti dokumentą. „Microsoft Office“ pasaulyje šie metaduomenys žinomi kaip dokumentų suvestinės informacija (angl. Document Summary Information).
Norint šią informaciją natūraliai išskirti „Delphi“ aplinkoje, nepasikliaujant OLE automatizavimu (kuriam reikalaujama, kad prieglobos kompiuteryje būtų įdiegtas „Excel“), reikia tiesiogiai analizuoti pagrindinę failo struktūrą. Šiame straipsnyje apžvelgsime, kaip veikia dokumentų suvestinės „Excel“ failuose ir kaip jas efektyviai išskirti naudojant neapdorotų srautų (angl. raw stream) analizę.
„Excel“ metaduomenų srautų supratimas
Istoriškai senesni „Excel“ failai (.xls) saugomi „OLE Compound Document“ formatu, kuris iš esmės veikia kaip mini failų sistema, talpinanti srautus ir saugyklas. Metaduomenys saugomi dviejuose specifiniuose srautuose:
SummaryInformation: talpina standartines savybes, tokias kaip pavadinimas, tema, autorius, raktažodžiai ir redakcijos numeris.DocumentSummaryInformation: talpina išplėstines savybes, tokias kaip įmonė, vadovas ir pasirinktinės vartotojo apibrėžtos savybės.
Šiuolaikiniai „Excel“ failai (.xlsx) naudoja „Office Open XML“ (OOXML) formatą, kuris yra suglaudinta XML struktūra. Metaduomenys čia yra saugomi failuose docProps/core.xml, docProps/app.xml ir docProps/custom.xml. Tvirtas „Delphi“ analizavimo komponentas turi sklandžiai apdoroti abi vidines struktūras ir kūrėjui pateikti vieningą API.
OLE sudėtinių dokumentų analizė „Delphi“ aplinkoje
Norint nuskaityti „SummaryInformation“ iš senojo formato .xls failo be trečiųjų šalių įrankių, turite išanalizuoti OLE struktūrinę saugyklą. „Microsoft“ tai atskleidžia per COM sąsają IPropertySetStorage. Štai neapdorotas „Delphi“ diegimas, padedantis išvengti „Excel“ paleidimo:
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;
Programinis išskyrimas su „HotXLS“
Nors „Windows COM API“ veikia seniesiems .xls failams, ji neveikia šiuolaikiniams .xlsx failams (kurie yra ZIP archyvai). Be to, naudoti COM API įvairiose platformose (pvz., „Linux“ ar „macOS“ per „FireMonkey“) yra neįmanoma. Naujausiuose „HotXLS“ komponento atnaujinimuose įdiegti specialūs moduliai (pvz., lxXlsSummary), skirti visiškai natūraliai (naudojant „Delphi“ kodą) izoliuoti ir optimizuoti šių suvestinės srautų skaitymą abiem formatams.
Kelių platformų pavyzdys
Naudodami XlsReadDocumentSummaryInformation ir XlsReadSummaryInformation sąsajas, galite greitai gauti metaduomenų eilutes tiek iš .xls, tiek iš .xlsx nesirūpindami pagrindine failų sistemos architektūra.
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;
Kodėl svarbus specializuotas suvestinės išskyrimas
Pagrindinis šio metodo privalumas yra našumas ir atminties saugumas. Išvengiant viso darbo knygos DOM (angl. Document Object Model) egzempliorių kūrimo ir analizuojant tik docProps/core.xml arba OLE savybių srautus, jūsų programos resursų naudojimas išlieka neįtikėtinai mažas. Jei indeksuojate 10 000 „Excel“ failų tinklo saugykloje, bandymas visiškai išanalizuoti kiekvieną iš jų išeikvos jūsų atmintį ir užtruks valandas. Specializuotas suvestinės išskyrimas tą pačią užduotį atlieka per kelias sekundes.
Be to, natūralus srautų skaitymas užtikrina, kad jūsų programa gali veikti kaip foninė paslauga arba be galvutės (angl. headless) „Linux“ serveryje niekada neiškviesdama „Excel.exe“, o tai yra esminis reikalavimas šiuolaikinėms keičiamo dydžio architektūroms.
Pastaba: išsamūs „Excel“ analizės ir metaduomenų išskyrimo įrankiai yra prieinami „HotXLS VCL“ komponente.