Peça a um pipeline para rotear dez mil folhas de cálculo por autor, empresa ou data de última modificação, e a pior coisa que ele pode fazer é abrir cada pasta de trabalho por completo. As respostas viajam nas propriedades de documento do ficheiro, o que o mundo do Office chama de Informações de Resumo do Documento: a camada de metadados que o Windows Search indexa, pela qual o SharePoint arquiva e que o Excel exibe em sua caixa de diálogo Propriedades. Essa camada tem, no máximo, alguns kilobytes, e vive em um lugar bem documentado em ambos os formatos do Excel. O truque é alcançá-la a partir do Delphi sem pagar pelo milhão de células de que você não precisa
Existem três rotas reais, e elas diferem menos no que retornam do que naquilo que exigem da máquina que as executa. A automação COM aciona o próprio Excel e lê tudo, a preço de desktop. O formato .xls mantém suas propriedades em fluxos de conjunto de propriedades OLE que o Windows analisa para você. O formato .xlsx as mantém em duas pequenas partes XML dentro de um zip que a RTL do Delphi consegue abrir sozinha. Segue o código funcional de cada uma, com os custos declarados sem rodeios
Rota 1: a automação COM lê tudo, a preço de desktop
A automação é a única rota com cobertura total através de um único modelo de objetos: o conjunto de resumo padrão, o conjunto estendido com Company e Manager, e as propriedades personalizadas definidas pelo utilizador, todos acessíveis por meio de BuiltinDocumentProperties e CustomDocumentProperties. Tudo chega como um OleVariant, e a API tem um hábito que vale a pena conhecer antes que ele te morda: uma propriedade interna que nunca foi atribuída não volta vazia, ela lança uma EOleException no instante em que você toca em Value. O auxiliar abaixo trata isso como "não definida" em vez de como uma falha
Agora a conta. O Excel precisa estar instalado em cada máquina em que este código roda, o que já descarta a maioria dos servidores por si só, e a política de suporte da Microsoft é explícita ao afirmar que o Office não é projetado nem licenciado para automação server-side desassistida. O CreateOleObject inicia um EXCEL.EXE completo e o Workbooks.Open analisa a pasta de trabalho inteira, então espere algo em torno de dois a quatro segundos por ficheiro antes que a primeira propriedade retorne. E o try..finally em volta do Quit não é enfeite: uma exceção que escape entre o CreateOleObject e o Quit deixa um EXCEL.EXE órfão segurando um lock sobre o ficheiro, invisível até que a próxima execução falhe contra ele. Reutilizar uma única instância do Excel ao longo de um lote amortiza o custo de arranque, mas concentra o risco, porque uma única caixa de diálogo perdida no desktop oculto trava todos os ficheiros enfileirados atrás dela
Rota 2: o .xls armazena propriedades em fluxos de conjunto de propriedades OLE
Uma pasta de trabalho BIFF8 é um ficheiro composto OLE, um sistema de ficheiros em miniatura de armazenamentos (storages) e fluxos (streams). Os dados das células vivem no fluxo Workbook; os metadados vivem ao lado, em dois fluxos de conjunto de propriedades cujos nomes começam com o caráter de controle #5: \005SummaryInformation para os campos clássicos e \005DocumentSummaryInformation para os estendidos e personalizados. Dentro de cada um há um conjunto de propriedades binário no layout MS-OLEPS, com seções indexadas por um identificador de formato (FMTID) e propriedades indexadas por um ID de propriedade inteiro. A seção de resumo é o FMTID {F29F85E0-4FF9-1068-AB91-08002B27B3D9}, onde PIDSI_TITLE é $02 e PIDSI_AUTHOR é $04; Company ($0F) e Manager ($0E) vivem na seção de resumo do documento, e as propriedades personalizadas em uma segunda seção atrás de um dicionário de nomes
A boa notícia é que no Windows você nunca analisa esses bytes você mesmo. O armazenamento estruturado expõe os fluxos por meio de IPropertySetStorage, e o código a seguir compila tal como mostrado contra as unidades de fábrica da RTL
Uma palavra honesta sobre o que o trecho esconde. As strings podem chegar como VT_LPWSTR ou como VT_LPSTR, e no caso ANSI os bytes são codificados na própria code page do conjunto de propriedades, ela mesma armazenada como propriedade 1 da seção, de modo que o cast acima só é exato quando essa code page coincide com a do sistema. Os carimbos de data e hora voltam como VT_FILETIME em UTC. As propriedades personalizadas significam abrir a seção definida pelo utilizador, FMTID {D5CDD505-2E9C-101B-9397-08002B2CF9AE}, e percorrer seu dicionário de nomes. O IPropertyStorage absorve tudo isso no Windows; escrever seu próprio parser MS-OLEPS para um ambiente sem armazenamento estruturado é um projeto de verdade, não uma tarde de trabalho
Rota 3: o .xlsx mantém docProps como XML dentro do zip
Esta é a rota de que a maioria dos pipelines realmente precisa, já que os ficheiros novos vêm em .xlsx há quase duas décadas. Uma pasta de trabalho OOXML é um pacote zip, e suas propriedades são divididas em pequenas partes por finalidade: docProps/core.xml contém os campos Dublin Core, dc:title, dc:creator, cp:lastModifiedBy, além de dcterms:created e dcterms:modified como carimbos de data e hora W3CDTF em UTC, enquanto docProps/app.xml contém campos de nível de aplicação, como Company e AppVersion, e docProps/custom.xml contém as propriedades personalizadas. Como o diretoria central do zip localiza cada parte diretamente, lê-las custa alguns poucos kilobytes, não importa o tamanho da pasta de trabalho. TZipFile e IXMLDocument, ambos na RTL entregue, fazem o trabalho todo
Dois detalhes mantêm isto robusto em produção. Primeiro, as partes são opcionais: um pacote mínimo sem nenhum docProps é perfeitamente válido sob a ECMA-376, e é por isso que o código sonda com IndexOf em vez de presumir. Segundo, faça a correspondência dos elementos por nome local e URI de namespace, como o FindNode faz acima, nunca por prefixo literal; dc: e cp: são convenções do gerador de escrita do Excel, e ficheiros produzidos por outros geradores têm liberdade para escolher prefixos diferentes. Uma observação ambiental: o fornecedor padrão do IXMLDocument é o MSXML, portanto uma aplicação de console ou uma thread de trabalho precisa chamar CoInitialize antes de LoadXMLData, ou a primeira análise morre com um erro COM
A folha de cálculo de custos, e quando uma biblioteca supera ambos os parsers
Medida em uma máquina de desenvolvedor comum, a rota COM fica em torno de dois a quatro segundos por ficheiro quando a sessão de automação é criada por ficheiro, quase tudo isso sendo a arranque do EXCEL.EXE mais a análise completa da pasta de trabalho, e ela exige um Excel instalado e licenciado onde quer que rode. As duas rotas diretas leem apenas os contêineres de metadados, terminam em milissegundos de um só dígito por ficheiro e não precisam de nada instalado além do que um executável Delphi já linka. Ao longo de um compartilhamento de dez mil ficheiros, essa é a diferença entre a maior parte de um dia de trabalho e menos de um minuto, sem nenhuma questão de implantação do Office anexada
O problema com as rotas diretas é que existem duas delas. Um pipeline que aceita ambos os formatos mantém dois parsers com dois modos de falha disjuntos, code pages e tipos PROPVARIANT de um lado, namespaces e partes opcionais do outro, e nenhum lê o formato do outro. Essa carga de manutenção é o argumento a favor de uma biblioteca nativa: o HotXLS, a biblioteca de folhas de cálculo em Object Pascal da losLab para Delphi e C++Builder no Windows, expõe os mesmos campos como propriedades comuns da pasta de trabalho, Title, Author, Company, Created e o resto, populados pelo Open tanto para .xls quanto para .xlsx, sem instalação do Excel e sem nada do encanamento de contêiner acima. Ele lê as propriedades como parte de uma abertura completa da pasta de trabalho, em vez de uma sondagem apenas de metadados, então se encaixa em pipelines que vão em seguida acessar os dados das células de qualquer forma; toda a superfície de propriedades em ambas as fachadas, incluindo o lado de escrita, é coberta em nosso artigo sobre como definir propriedades de documento do Excel com HotXLS
Nota: Ferramentas completas de análise do Excel e extração de metadados estão disponíveis no HotXLS VCL Component