Ao processar grandes lotes de folhas de cálculo Excel num canal automatizado, raramente quer carregar todo o documento para a memória apenas para descobrir o que é. Muitas vezes, os metadados incorporados no ficheiro, autor, título, data de criação e propriedades personalizadas, são suficientes para encaminhar, indexar ou rejeitar o documento. No mundo do Microsoft Office, estes metadados são conhecidos como Informação de Resumo do Documento (Document Summary Information).
Extrair estas informações nativamente em Delphi sem depender da automação OLE (que requer que o Excel esteja instalado na máquina anfitriã) exige a análise direta da estrutura subjacente do ficheiro. Neste artigo, veremos como funcionam os resumos de documentos em ficheiros Excel e como extraí-los eficientemente utilizando a análise de fluxo (stream parsing) em bruto.
Compreender os Fluxos de Metadados do Excel
Historicamente, os ficheiros Excel mais antigos (.xls) são guardados nos formatos OLE Compound Document, agindo efetivamente como mini sistemas de ficheiros contendo fluxos (streams) e armazenamentos (storages). Os metadados estão alojados em dois fluxos específicos:
SummaryInformation: Contém propriedades padrão como Título, Assunto, Autor, Palavras-chave e Número de Revisão.DocumentSummaryInformation: Contém propriedades estendidas como Empresa, Gestor e propriedades personalizadas definidas pelo utilizador.
Os ficheiros Excel modernos (.xlsx) utilizam o formato Office Open XML (OOXML), que é uma estrutura XML comprimida. Os metadados aqui estão localizados em docProps/core.xml, docProps/app.xml e docProps/custom.xml. Um componente robusto de análise em Delphi deve lidar perfeitamente com ambas as estruturas internas enquanto expõe uma API unificada ao programador.
Analisar Documentos Compostos OLE em Delphi
Para ler a SummaryInformation de um ficheiro legado `.xls` sem ferramentas de terceiros, precisa de analisar o OLE Structured Storage. A Microsoft expõe isto através da interface COM IPropertySetStorage. Eis uma implementação Delphi em bruto que evita arrancar o 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;
Extração Programática com HotXLS
Embora a API COM do Windows funcione para ficheiros `.xls`, não funciona para ficheiros modernos `.xlsx` (que são arquivos ZIP). Além disso, utilizar a API COM multiplataforma (por exemplo, em Linux ou macOS via FireMonkey) é impossível. Atualizações recentes ao componente HotXLS introduziram unidades dedicadas (por exemplo, lxXlsSummary) para isolar e otimizar a leitura destes fluxos de resumo em ambos os formatos de forma completamente nativa em código Delphi.
Um Exemplo Multiplataforma
Utilizando as interfaces XlsReadDocumentSummaryInformation e XlsReadSummaryInformation, pode recolher rapidamente as cadeias de metadados de `.xls` e `.xlsx` sem se preocupar com a arquitetura do sistema de ficheiros subjacente.
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 Que Razão a Extração Dedicada de Resumos é Importante
O principal benefício desta abordagem é o desempenho e a segurança da memória. Ao evitar a instanciação do DOM (Document Object Model) do livro de trabalho completo e analisando apenas o docProps/core.xml ou os fluxos de propriedade OLE, a pegada da sua aplicação permanece incrivelmente pequena. Se estiver a indexar 10.000 ficheiros Excel numa partilha de rede, tentar analisar completamente cada um irá esgotar a sua memória e demorará horas. A extração dedicada de resumos conclui a mesma tarefa em segundos.
Além disso, a leitura nativa dos fluxos garante que a sua aplicação pode ser executada como um serviço de fundo (background service) ou num servidor Linux headless sem nunca invocar o Excel.exe, o que é um requisito crítico para arquiteturas escaláveis modernas.
Nota: Ferramentas abrangentes de análise de Excel e extração de metadados estão disponíveis no Componente HotXLS VCL.