Når du behandler store partier af Excel-regneark i en automatiseret pipeline, ønsker du sjældent at indlæse hele dokumentet i hukommelsen bare for at finde ud af, hvad det er. Ofte er de metadata, der er indlejret i filen, forfatter, titel, oprettelsesdato og brugerdefinerede egenskaber, nok til at dirigere, indeksere eller afvise dokumentet. I Microsoft Office-verdenen er disse metadata kendt som Document Summary Information.
At udtrække denne information direkte i Delphi uden at stole på OLE-automatisering (som kræver, at Excel er installeret på værtsmaskinen) kræver, at den underliggende filstruktur parses direkte. I denne artikel vil vi se på, hvordan dokumentsummeringer fungerer i Excel-filer, og hvordan man udtrækker dem effektivt ved hjælp af rå stream-parsing.
Forståelse af Excel metadata-streams
Historisk set gemmes ældre Excel-filer (.xls) i OLE Compound Document-formater, som effektivt fungerer som små filsystemer, der indeholder streams og lagre. Metadataene er placeret i to specifikke streams:
SummaryInformation: Indeholder standardegenskaber som titel, emne, forfatter, nøgleord og revisionsnummer.DocumentSummaryInformation: Indeholder udvidede egenskaber som virksomhed, leder og brugerdefinerede egenskaber.
Moderne Excel-filer (.xlsx) bruger Office Open XML (OOXML)-formatet, som er en zippet XML-struktur. Metadataene her findes i docProps/core.xml, docProps/app.xml og docProps/custom.xml. En robust Delphi-parsingkomponent skal gnidningsløst håndtere begge interne strukturer, mens den eksponerer en samlet API for udvikleren.
Parsing af OLE Compound Documents i Delphi
For at læse SummaryInformation fra en ældre .xls-fil uden tredjepartsværktøjer, skal du parse OLE Structured Storage. Microsoft eksponerer dette gennem COM-grænsefladen IPropertySetStorage. Her er en rå Delphi-implementering, der undgår at starte 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;
Programmatisk udtrækning med HotXLS
Selvom Windows COM API fungerer for .xls-filer, fungerer det ikke for moderne .xlsx-filer (som er ZIP-arkiver). Desuden er brug af COM API på tværs af platforme (f.eks. på Linux eller macOS via FireMonkey) umuligt. Nylige opdateringer til HotXLS-komponenten introducerede dedikerede enheder (f.eks. lxXlsSummary) for at isolere og optimere læsningen af disse summerings-streams på tværs af begge formater, helt og holdent i indfødt Delphi-kode.
Et tværplatformseksempel
Ved hjælp af XlsReadDocumentSummaryInformation og XlsReadSummaryInformation-grænsefladerne kan du hurtigt gribe metadata-strengene fra både .xls og .xlsx uden at bekymre dig om den underliggende filsystemarkitektur.
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;
Hvorfor dedikeret udtrækning af summering er vigtig
Den primære fordel ved denne tilgang er ydeevne og hukommelsessikkerhed. Ved at undgå instantiering af den fulde arbejdsbog-DOM (Document Object Model) og kun parse docProps/core.xml eller OLE-egenskabs-streams, forbliver din applikations fodaftryk utroligt lille. Hvis du indekserer 10.000 Excel-filer på tværs af et netværksdrev, vil forsøg på at parse hver enkelt fuldt ud belaste din hukommelse og tage timer. Dedikeret udtrækning af summering fuldfører den samme opgave på sekunder.
Desuden sikrer indfødt læsning af streams, at din applikation kan køre som en baggrundstjeneste eller på en hovedløs Linux-server uden nogensinde at aktivere Excel.exe, hvilket er et kritisk krav for moderne skalerbare arkitekturer.
Bemærk: Omfattende Excel-parsing og værktøjer til metadataudtrækning er tilgængelige i HotXLS VCL Component.