Apdorojant dideles „Excel“ skaičiuoklių partijas automatizuotame konvejeryje (angl. automated pipeline), retai norima įkelti visą dokumentą į atmintį vien tam, kad išsiaiškintumėte, kas tai yra. Dažnai faile įterptų metaduomenų (autorius, pavadinimas, sukūrimo data ir pasirinktinės savybės) pakanka dokumentui nukreipti, indeksuoti arba atmesti. „Microsoft Office“ pasaulyje šie metaduomenys žinomi kaip Dokumentų suvestinės informacija (angl. Document Summary Information)
Norint išgauti šią informaciją natūraliai Delphi aplinkoje, nepasikliaujant OLE automatizavimu (kuris reikalauja, kad pagrindiniame kompiuteryje būtų įdiegtas „Excel“), reikia tiesiogiai analizuoti (angl. parse) pagrindinę failo struktūrą. Tolesniuose skyriuose aptariama, kaip dokumentų suvestinės saugomos „Excel“ failuose ir kaip jas efektyviai išskirti naudojant tiesioginį srautų analizavimą
„Excel“ metaduomenų srautų supratimas
Istoriškai senesni „Excel“ failai (.xls) saugomi „OLE Compound Document“ formatu, veiksmingai veikiančiu kaip mini failų sistemos, turinčios srautus ir saugyklas. Metaduomenys saugomi dviejuose specifiniuose srautuose:
SummaryInformation: Sudėtyje yra standartinės savybės, tokios kaip Pavadinimas, Tema, Autorius, Raktiniai žodžiai ir Versijos numerisDocumentSummaryInformation: Sudėtyje yra išplėstinės savybės, tokios 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. Čia metaduomenys yra docProps/core.xml, docProps/app.xml ir docProps/custom.xml failuose. Patikimas Delphi analizavimo komponentas turi apdoroti abi vidines struktūras be papildomo skambinančiojo darbo, tuo pačiu kūrėjui atskleisdamas vieningą API
OLE sudėtinių dokumentų analizavimas Delphi aplinkoje
Norėdami perskaityti SummaryInformation iš senojo .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 tiesioginė Delphi realizacija, leidžianti 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 .xls failams, jis neveikia šiuolaikiniams .xlsx failams (kurie yra ZIP archyvai). Be to, naudoti COM API įvairiose platformose (pvz., Linux ar macOS per FireMonkey) yra neįmanoma. Naujausi HotXLS komponento atnaujinimai įvedė dedikuotus modulius (pvz., lxXlsSummary), siekiant izoliuoti ir optimizuoti šių suvestinės srautų skaitymą abiejuose formatuose visiškai natūraliai Delphi kode
Daugiaplatformis pavyzdys
Naudodami XlsReadDocumentSummaryInformation ir XlsReadSummaryInformation sąsajas, galite greitai paimti metaduomenų eilutes iš .xls ir .xlsx, nesijaudindami dėl pagrindinės failų sistemos architektūros
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 dedikuotas suvestinės išskyrimas yra svarbus
Pagrindinis šio požiūrio privalumas yra našumas ir atminties saugumas. Išvengiant pilno darbo knygos DOM (Document Object Model) egzemplioriaus sukūrimo ir analizuojant tik docProps/core.xml arba OLE savybių srautus, jūsų programos pėdsakas išlieka neįtikėtinai mažas. Jei indeksuojate 10 000 „Excel“ failų tinklo diske, bandymas pilnai išanalizuoti kiekvieną iš jų išeikvos jūsų atmintį ir užtruks valandas. Dedikuotas 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ė tarnyba arba „Linux“ serveryje be vaizduoklio (angl. headless), niekada neiškviečiant Excel.exe – tai kritinis reikalavimas šiuolaikinėms keičiamo mastelio (angl. scalable) architektūroms
Pastaba: Pilni „Excel“ analizavimo ir metaduomenų išskyrimo įrankiai yra prieinami HotXLS VCL komponente