När du bearbetar stora mängder Excel-kalkylblad i en automatiserad pipeline vill du sällan läsa in hela dokumentet i minnet bara för att ta reda på vad det är. Ofta räcker den metadata som är inbäddad i filen (som författare, titel, skapandedatum och anpassade egenskaper) för att dirigera, indexera eller avvisa dokumentet. I Microsoft Office-världen kallas denna metadata för Document Summary Information (dokumentsammanfattning).
Att extrahera denna information inbyggt i Delphi utan att förlita sig på OLE-automatisering (vilket kräver att Excel är installerat på värdmaskinen) kräver att man tolkar den underliggande filstrukturen direkt. I den här artikeln kommer vi att titta på hur dokumentsammanfattningar fungerar i Excel-filer och hur man extraherar dem effektivt med hjälp av rå strömtolkning (raw stream parsing).
Förstå Excels metadata-strömmar
Historiskt sett lagras äldre Excel-filer (.xls) i OLE Compound Document-format, vilket i praktiken fungerar som mini-filsystem som innehåller strömmar och lagringar. Metadatan är inrymd i två specifika strömmar:
SummaryInformation: Innehåller standardegenskaper som titel, ämne, författare, nyckelord och revisionsnummer.DocumentSummaryInformation: Innehåller utökade egenskaper som företag, chef och anpassade användardefinierade egenskaper.
Moderna Excel-filer (.xlsx) använder formatet Office Open XML (OOXML), som är en zippad XML-struktur. Metadatan här finns i docProps/core.xml, docProps/app.xml och docProps/custom.xml. En robust Delphi-tolkningskomponent måste sömlöst hantera båda interna strukturerna samtidigt som den exponerar ett enhetligt API för utvecklaren.
Tolka OLE Compound Documents i Delphi
För att läsa SummaryInformation från en äldre .xls-fil utan tredjepartsverktyg måste du tolka OLE Structured Storage. Microsoft exponerar detta genom COM-gränssnittet IPropertySetStorage. Här är en rå Delphi-implementering som undviker att starta 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 extraktion med HotXLS
Även om Windows COM API fungerar för .xls-filer, fungerar det inte för moderna .xlsx-filer (som är ZIP-arkiv). Dessutom är det omöjligt att använda COM API över flera plattformar (t.ex. på Linux eller macOS via FireMonkey). Nya uppdateringar av HotXLS-komponenten introducerade dedikerade enheter (t.ex. lxXlsSummary) för att isolera och optimera läsningen av dessa sammanfattningsströmmar i båda formaten, helt inbyggt i Delphi-kod.
Ett exempel för flera plattformar
Genom att använda gränssnitten XlsReadDocumentSummaryInformation och XlsReadSummaryInformation kan du snabbt hämta metadatasträngarna från både .xls och .xlsx utan att behöva oroa dig för den underliggande filsystemsarkitekturen.
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;
Varför dedikerad sammanfattningsextraktion är viktigt
Den främsta fördelen med denna metod är prestanda och minnessäkerhet. Genom att undvika instansiering av den fullständiga DOM:en (Document Object Model) för arbetsboken och endast tolka docProps/core.xml eller OLE-egenskapsströmmarna, förblir applikationens fotavtryck otroligt litet. Om du indexerar 10 000 Excel-filer över en nätverksdelning kommer försök att tolka varje fil fullt ut att förstöra ditt minne och ta timmar. Dedikerad sammanfattningsextraktion slutför samma uppgift på sekunder.
Dessutom säkerställer inbyggd läsning av strömmarna att din applikation kan köras som en bakgrundstjänst eller på en headless Linux-server utan att någonsin anropa Excel.exe – ett kritiskt krav för moderna skalbara arkitekturer.
Obs: Omfattande verktyg för Excel-tolkning och metadataextraktion finns tillgängliga i HotXLS VCL Component.