Al procesar grandes lotes de hojas de cálculo de Excel en una canalización automatizada, rara vez se desea cargar todo el documento en la memoria solo para averiguar de qué se trata. A menudo, los metadatos integrados en el archivo (autor, título, fecha de creación y propiedades personalizadas) son suficientes para enrutar, indexar o rechazar el documento. En el mundo de Microsoft Office, estos metadatos se conocen como Información de resumen del documento.
Extraer esta información de forma nativa en Delphi sin depender de la automatización OLE (que requiere que Excel esté instalado en la máquina host) requiere analizar la estructura subyacente del archivo directamente. En este artículo, veremos cómo funcionan los resúmenes de documentos en los archivos de Excel y cómo extraerlos de manera eficiente mediante el análisis de flujo sin procesar.
Comprensión de los flujos de metadatos de Excel
Históricamente, los archivos de Excel más antiguos (.xls) se almacenan en formatos de documento compuesto OLE, actuando efectivamente como minisistemas de archivos que contienen flujos y almacenamientos. Los metadatos se alojan en dos flujos específicos:
SummaryInformation: contiene propiedades estándar como título, asunto, autor, palabras clave y número de revisión.DocumentSummaryInformation: contiene propiedades extendidas como empresa, gerente y propiedades personalizadas definidas por el usuario.
Los archivos de Excel modernos (.xlsx) utilizan el formato Office Open XML (OOXML), que es una estructura XML comprimida. Los metadatos aquí se encuentran en docProps/core.xml, docProps/app.xml y docProps/custom.xml. Un componente de análisis de Delphi robusto debe manejar a la perfección ambas estructuras internas al tiempo que expone una API unificada al desarrollador.
Análisis de documentos compuestos OLE en Delphi
Para leer la SummaryInformation de un archivo `.xls` heredado sin herramientas de terceros, debe analizar el almacenamiento estructurado OLE. Microsoft expone esto a través de la interfaz COM IPropertySetStorage. Aquí hay una implementación de Delphi sin procesar 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
Si bien la API COM de Windows funciona para archivos `.xls`, no funciona para los archivos modernos `.xlsx` (que son archivos ZIP). Además, el uso de la API COM multiplataforma (por ejemplo, en Linux o macOS a través de FireMonkey) es imposible. Las actualizaciones recientes del componente HotXLS introdujeron unidades dedicadas (por ejemplo, lxXlsSummary) para aislar y optimizar la lectura de estos flujos de resumen en ambos formatos de forma completamente nativa en el código Delphi.
Un ejemplo multiplataforma
Al utilizar las interfaces XlsReadDocumentSummaryInformation y XlsReadSummaryInformation, puede obtener rápidamente las cadenas de metadatos de los archivos `.xls` y `.xlsx` sin preocuparse por la arquitectura del sistema de archivos subyacente.
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é es importante la extracción de resúmenes dedicada
El beneficio principal de este enfoque es el rendimiento y la seguridad de la memoria. Al evitar la creación de instancias del DOM (Modelo de objetos de documento) del libro de trabajo completo y analizar solo el docProps/core.xml o los flujos de propiedades OLE, la huella de su aplicación sigue siendo increíblemente pequeña. Si está indexando 10 000 archivos de Excel en un recurso compartido de red, intentar analizar completamente cada uno agotará su memoria y tomará horas. La extracción de resúmenes dedicada completa la misma tarea en segundos.
Además, la lectura nativa de los flujos garantiza que su aplicación pueda ejecutarse como un servicio en segundo plano o en un servidor Linux sin interfaz gráfica sin invocar nunca a Excel.exe, un requisito fundamental para las arquitecturas escalables modernas.
Nota: Las herramientas integrales de análisis de Excel y extracción de metadatos están disponibles en el componente HotXLS VCL.