Be en pipeline dirigera tiotusen kalkylblad efter författare, företag eller datum för senaste ändring, så är det värsta den kan göra att öppna varje arbetsbok fullständigt. Svaren finns i filens dokumentegenskaper, det som Office-världen kallar Document Summary Information: metadatalagret som Windows Search indexerar, som SharePoint sorterar filer efter och som Excel visar i dialogrutan Egenskaper. Lagret är högst några kilobyte och finns på en väldokumenterad plats i båda Excel-formaten. Utmaningen är att nå det från Delphi utan att betala för de miljoner celler du inte behöver
Det finns tre verkliga vägar, och de skiljer sig mindre åt i vad de returnerar än i vad de kräver av maskinen där de körs. COM-automatisering styr själva Excel och läser allt, till kostnaden av en stationär miljö. Formatet .xls lagrar egenskaperna i OLE-egenskapsströmmar som Windows kan tolka åt dig. Formatet .xlsx lagrar dem i två små XML-delar i ett zip-arkiv som Delphis RTL kan öppna själv. Här följer fungerande kod för varje väg, med kostnaderna tydligt angivna
De tre aktuella läsvägarna
COM-automatisering ger full täckning via BuiltinDocumentProperties och CustomDocumentProperties, inklusive Company, Manager och anpassade egenskaper. Värdena kommer som OleVariant, och en inbyggd egenskap som aldrig har tilldelats kan kasta EOleException när Value läses. Excel måste vara installerat och try..finally måste alltid nå Quit, annars kan ett övergivet EXCEL.EXE behålla en fillåsning
För BIFF8 och .xls ligger cellerna i strömmen Workbook, medan egenskaperna finns i \005SummaryInformation och \005DocumentSummaryInformation. FMTID {F29F85E0-4FF9-1068-AB91-08002B27B3D9} identifierar sammanfattningssektionen, där PIDSI_TITLE är $02 och PIDSI_AUTHOR är $04; Company ($0F) och Manager ($0E) finns i dokumentsammanfattningen. Windows exponerar detta via IPropertySetStorage; strängar kan vara VT_LPSTR eller VT_LPWSTR, medan tidsstämplar kommer som VT_FILETIME i UTC
För .xlsx finns egenskaperna i zip-delarna docProps/core.xml, docProps/app.xml och docProps/custom.xml. dc:title, dc:creator, cp:lastModifiedBy, dcterms:created och dcterms:modified ligger i kärnegenskaperna, medan Company och AppVersion ligger i app-egenskaperna. Använd TZipFile och IXMLDocument, kontrollera valfria delar med IndexOf, matcha efter namnrymds-URI och anropa CoInitialize före LoadXMLData i konsolprogram och arbetstrådar
COM-vägen tar ungefär två till fyra sekunder per fil när Excel startas per fil och kräver ett installerat, licensierat Excel. De direkta vägarna läser bara metadatabehållarna och blir normalt klara på ensiffriga millisekunder. För en pipeline som accepterar båda formaten innebär det dock två separata tolkar och felbilder; HotXLS kan i stället exponera samma arbetsboksegenskaper för både .xls och .xlsx utan Excel-installation
uses
System.SysUtils, System.Variants, System.Win.ComObj;
procedure ReadPropertiesViaCom(const FileName: string);
var
Excel, Book, Builtin, Custom: OleVariant;
I: Integer;
begin
Excel := CreateOleObject('Excel.Application');
try
Excel.DisplayAlerts := False;
Book := Excel.Workbooks.Open(FileName, 0, True); // read-only
try
Builtin := Book.BuiltinDocumentProperties;
Custom := Book.CustomDocumentProperties;
for I := 1 to Custom.Count do
Writeln(VarToStr(Custom.Item(I).Name), ' = ',
VarToStr(Custom.Item(I).Value));
finally
Book.Close(False);
end;
finally
Excel.Quit; // reach this on every path, or EXCEL.EXE stays behind
Excel := Unassigned;
end;
end;
Väg 1: COM-automatisering läser allt, till kostnaden av en skrivbordsmiljö
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 revisionsnummerDocumentSummaryInformation: 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