Ko v avtomatiziranem cevovodu obdelujete velike serije Excelovih preglednic, redkokdaj želite naložiti celoten dokument v pomnilnik samo zato, da bi ugotovili, za kaj gre. Pogosto zadostujejo metapodatki, vdelani v datoteko (avtor, naslov, datum ustvarjanja in lastnosti po meri), da dokument usmerite, indeksirate ali zavrnete. V svetu Microsoft Officea so ti metapodatki znani kot Informacije o povzetku dokumenta (Document Summary Information).
Za izvorno pridobivanje teh informacij v Delphiju brez zanašanja na avtomatizacijo OLE (ki zahteva, da je na gostiteljskem računalniku nameščen Excel) je treba neposredno razčleniti osnovno strukturo datoteke. V tem članku si bomo ogledali, kako delujejo povzetki dokumentov v Excelovih datotekah in kako jih učinkovito pridobiti z uporabo razčlenjevanja surovih tokov.
Razumevanje tokov Excelovih metapodatkov
Zgodovinsko gledano so starejše Excelove datoteke (.xls) shranjene v formatih OLE Compound Document, ki dejansko delujejo kot mini datotečni sistemi, ki vsebujejo tokove in shrambe. Metapodatki so shranjeni v dveh specifičnih tokovih:
SummaryInformation: Vsebuje standardne lastnosti, kot so naslov, zadeva, avtor, ključne besede in številka revizije.DocumentSummaryInformation: Vsebuje razširjene lastnosti, kot sta podjetje, vodja in lastnosti po meri, ki jih določi uporabnik.
Sodobne Excelove datoteke (.xlsx) uporabljajo format Office Open XML (OOXML), ki je stisnjena struktura XML. Tu se metapodatki nahajajo v docProps/core.xml, docProps/app.xml in docProps/custom.xml. Robustna komponenta za razčlenjevanje v Delphiju mora brez težav obravnavati oboje notranje strukture in hkrati razvijalcu izpostaviti enoten API.
Razčlenjevanje OLE Compound dokumentov v Delphiju
Za branje informacij SummaryInformation iz starejše datoteke `.xls` brez orodij tretjih oseb morate razčleniti shrambo OLE Structured Storage. Microsoft to izpostavlja prek vmesnika COM IPropertySetStorage. Tukaj je surova implementacija v Delphiju, ki se izogne zagonu Excela:
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;
Programsko pridobivanje s HotXLS
Medtem ko Windows COM API deluje za datoteke `.xls`, ne deluje za sodobne datoteke `.xlsx` (ki so ZIP arhivi). Poleg tega je uporaba COM API-ja na več platformah (npr. v Linuxu ali macOS prek FireMonkey) nemogoča. Nedavne posodobitve komponente HotXLS so uvedle namenske enote (npr. lxXlsSummary) za izolacijo in optimizacijo branja teh tokov povzetkov v obeh formatih povsem izvorno v kodi Delphi.
Primer za več platform
Z uporabo vmesnikov XlsReadDocumentSummaryInformation in XlsReadSummaryInformation lahko hitro preberete nize metapodatkov iz datotek `.xls` in `.xlsx`, ne da bi vas skrbela arhitektura osnovnega datotečnega sistema.
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;
Zakaj je namensko pridobivanje povzetkov pomembno
Glavna prednost tega pristopa je zmogljivost in varnost pomnilnika. Z izogibanjem instanciaciji celotnega DOM-a (Document Object Model) delovnega zvezka in razčlenjevanjem samo datotek docProps/core.xml ali tokov lastnosti OLE ostane odtis vaše aplikacije neverjetno majhen. Če indeksirate 10.000 Excelovih datotek v omrežni skupni rabi, bo poskus popolne razčlenitve vsake izmed njih močno obremenil vaš pomnilnik in trajal več ur. Namensko pridobivanje povzetkov opravi isto nalogo v nekaj sekundah.
Poleg tega izvorno branje tokov zagotavlja, da se lahko vaša aplikacija izvaja kot storitev v ozadju ali na strežniku Linux brez grafičnega vmesnika, ne da bi pri tem kdaj klicala Excel.exe, kar je kritična zahteva za sodobne razširljive arhitekture.
Opomba: Obsežna orodja za razčlenjevanje Excelovih datotek in pridobivanje metapodatkov so na voljo v komponenti HotXLS VCL Component.