Cuando se procesa un gran volumen de hojas de cálculo de Excel en una canalización automatizada, casi nunca conviene cargar el documento completo en memoria solo para descubrir de qué trata. En muchos casos, los metadatos incorporados en el archivo, como autor, título, fecha de creación y propiedades personalizadas, alcanzan para enrutar, indexar o descartar el documento. En el entorno de Microsoft Office, ese conjunto se conoce como Document Summary Information (información de resumen del documento)
Extraer esa información de forma nativa en Delphi, sin depender de automatización OLE ni de tener Excel instalado en la máquina anfitriona, exige leer directamente la estructura interna del archivo. En este artículo verá cómo funcionan los resúmenes de documentos en los archivos de Excel y cómo extraerlos de forma eficiente mediante análisis directo de flujos
Cómo funcionan los flujos de metadatos de Excel
En los archivos de Excel más antiguos (.xls), los datos se guardan en un formato de documento compuesto OLE que actúa como un sistema de archivos en miniatura con flujos y almacenes. Los metadatos viven en dos flujos concretos:
SummaryInformation: contiene propiedades estándar como título, asunto, autor, palabras clave y número de revisiónDocumentSummaryInformation: contiene propiedades extendidas como empresa, gerente y propiedades personalizadas definidas por el usuario
Los archivos modernos de Excel (.xlsx) usan el formato Office Open XML (OOXML), una estructura XML comprimida. En ese caso, los metadatos se encuentran en docProps/core.xml, docProps/app.xml y docProps/custom.xml. Un componente sólido de análisis en Delphi debe reconocer sin problemas ambas estructuras y ofrecer una API unificada al desarrollador
Análisis de documentos compuestos OLE en Delphi
Para leer SummaryInformation de un archivo .xls heredado sin depender de herramientas de terceros, hace falta analizar el almacenamiento estructurado OLE. Microsoft expone esa capacidad mediante la interfaz COM IPropertySetStorage. A continuación se muestra una implementación directa en Delphi que evita iniciar 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;
Extracción programática con HotXLS
La API COM de Windows funciona para archivos .xls, pero no para los .xlsx modernos, que en realidad son archivos ZIP. Además, llevar esa ruta COM a un entorno multiplataforma, como Linux o macOS con FireMonkey, no es viable. Las versiones recientes de HotXLS incorporaron unidades dedicadas, por ejemplo lxXlsSummary, para aislar y optimizar la lectura de esos flujos de resumen en ambos formatos de manera nativa en Delphi
Un ejemplo multiplataforma
Con las interfaces XlsReadDocumentSummaryInformation y XlsReadSummaryInformation, puede capturar rápidamente las cadenas de metadatos tanto de .xls como de .xlsx sin preocuparse por la arquitectura interna del archivo
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;
Por qué conviene extraer resúmenes de forma dedicada
La ventaja principal de este enfoque es el rendimiento y la seguridad de memoria. Si evita crear todo el modelo de objetos del libro y se limita a leer docProps/core.xml o los flujos de propiedades OLE, su aplicación se mantiene mucho más liviana. Cuando se indexan 10 000 archivos de Excel en un recurso compartido de red, intentar analizarlos por completo agota la memoria y consume horas. La extracción dedicada hace el mismo trabajo en segundos
Además, leer los flujos de forma nativa permite ejecutar la aplicación como servicio en segundo plano o en un servidor Linux sin interfaz gráfica, sin invocar nunca a Excel.exe, algo clave para arquitecturas modernas y escalables
Nota: Las herramientas completas para analizar y extraer metadatos de Excel están disponibles en el HotXLS VCL Component