Technical Article

Extragerea informațiilor de sumar ale documentului din fișiere Excel în Delphi

Atunci când procesați loturi mari de foi de calcul Excel într-un flux automatizat, rareori doriți să încărcați întregul document în memorie doar pentru a afla ce este. Adesea, metadatele încorporate în fișier (autorul, titlul, data creării și proprietățile personalizate) sunt suficiente pentru a direcționa, indexa sau respinge documentul. În lumea Microsoft Office, aceste metadate sunt cunoscute sub numele de Document Summary Information (Informații de sumar ale documentului).

Extragerea acestor informații nativ în Delphi fără a vă baza pe automatizarea OLE (care necesită ca Excel să fie instalat pe mașina gazdă) necesită parsarea directă a structurii fișierului de bază. În acest articol, vom analiza modul în care funcționează sumarele de documente în fișierele Excel și cum să le extragem eficient utilizând parsarea directă a fluxurilor.

Înțelegerea fluxurilor de metadate Excel

Din punct de vedere istoric, fișierele Excel mai vechi (.xls) sunt stocate în formate OLE Compound Document, acționând efectiv ca niște mini-sisteme de fișiere care conțin fluxuri și zone de stocare. Metadatele sunt găzduite în două fluxuri specifice:

  • SummaryInformation: Conține proprietăți standard precum Title, Subject, Author, Keywords și Revision Number.
  • DocumentSummaryInformation: Conține proprietăți extinse, cum ar fi Company, Manager și proprietăți personalizate definite de utilizator.

Fișierele Excel moderne (.xlsx) utilizează formatul Office Open XML (OOXML), care este o structură XML arhivată tip ZIP. Metadatele aici se află în docProps/core.xml, docProps/app.xml și docProps/custom.xml. O componentă robustă de parsare Delphi trebuie să gestioneze impecabil ambele structuri interne, expunând în același timp un API unificat dezvoltatorului.

Parsarea documentelor compuse OLE în Delphi

Pentru a citi informațiile de sumar dintr-un fișier `.xls` moștenit fără instrumente de la terți, trebuie să parsați stocarea structurată OLE (OLE Structured Storage). Microsoft expune acest lucru prin interfața COM IPropertySetStorage. Iată o implementare Delphi de bază care evită pornirea 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;

Extragerea programatică cu HotXLS

Deși API-ul Windows COM funcționează pentru fișierele `.xls`, nu funcționează pentru fișierele moderne `.xlsx` (care sunt arhive ZIP). Mai mult, utilizarea API-ului COM pe mai multe platforme (de exemplu, pe Linux sau macOS prin FireMonkey) este imposibilă. Actualizările recente ale componentei HotXLS au introdus unități dedicate (de exemplu, lxXlsSummary) pentru a izola și a optimiza citirea acestor fluxuri de sumar în ambele formate, complet nativ în cod Delphi.

Un exemplu multiplatformă

Utilizând interfețele XlsReadDocumentSummaryInformation și XlsReadSummaryInformation, puteți prelua rapid metadatele tip șir din ambele formate, `.xls` și `.xlsx`, fără să vă faceți griji cu privire la arhitectura sistemului de fișiere subiacent.

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;

De ce contează extragerea dedicată a sumarului

Beneficiul principal al acestei abordări este performanța și siguranța memoriei. Evitând instanțierea întregului DOM (Document Object Model) al registrului de lucru și parsând doar docProps/core.xml sau fluxurile de proprietăți OLE, amprenta aplicației dumneavoastră rămâne incredibil de mică. Dacă indexați 10.000 de fișiere Excel într-o rețea partajată, încercarea de a parsa complet fiecare fișier vă va epuiza memoria și va dura ore întregi. Extragerea dedicată a sumarului finalizează aceeași sarcină în câteva secunde.

Mai mult, citirea nativă a fluxurilor asigură faptul că aplicația dumneavoastră poate rula ca un serviciu de fundal sau pe un server Linux fără interfață grafică (headless), fără a apela vreodată Excel.exe, o cerință critică pentru arhitecturile scalabile moderne.

Notă: Instrumente cuprinzătoare pentru parsarea Excel și extragerea metadatelor sunt disponibile în HotXLS VCL Component.