Technical Article

Dokumentumösszegző információk kinyerése Excel fájlokból Delphiben

Nagy mennyiségű Excel táblázat automatizált feldolgozásakor ritkán akarja a teljes dokumentumot betölteni a memóriába csak azért, hogy kiderítse, mi az. Gyakran a fájlba ágyazott metaadatok—szerző, cím, létrehozás dátuma és egyéni tulajdonságok—is elegendőek a dokumentum irányításához, indexeléséhez vagy elutasításához. A Microsoft Office világában ezeket a metaadatokat Dokumentumösszegző információknak (Document Summary Information) nevezik.

Ezeknek az információknak a natív kinyerése Delphiben anélkül, hogy az OLE automatizálásra (amely megköveteli az Excel telepítését a gazdagépen) támaszkodna, az alapul szolgáló fájlszerkezet közvetlen elemzését igényli. Ebben a cikkben megvizsgáljuk, hogyan működnek a dokumentumösszegzők az Excel fájlokban, és hogyan lehet őket hatékonyan kinyerni nyers streamelemzéssel.

Excel metaadat streamek megértése

Történelmileg a régebbi Excel fájlokat (.xls) OLE Compound Document formátumban tárolták, amelyek lényegében mini fájlrendszerként működnek, streameket és tárolókat (storages) tartalmazva. A metaadatok két specifikus streamben találhatók:

  • SummaryInformation: Olyan szabványos tulajdonságokat tartalmaz, mint a Cím (Title), Tárgy (Subject), Szerző (Author), Kulcsszavak (Keywords) és a Revízió száma.
  • DocumentSummaryInformation: Olyan bővített tulajdonságokat tartalmaz, mint a Vállalat (Company), Menedzser (Manager), valamint egyéni, felhasználó által definiált tulajdonságok.

A modern Excel fájlok (.xlsx) az Office Open XML (OOXML) formátumot használják, amely egy tömörített XML struktúra. Itt a metaadatok a docProps/core.xml, docProps/app.xml és docProps/custom.xml fájlokban találhatók. Egy robusztus Delphi elemző komponensnek zökkenőmentesen kell kezelnie mindkét belső struktúrát, miközben egységes API-t biztosít a fejlesztő számára.

OLE Compound Documents elemzése Delphiben

A SummaryInformation beolvasásához egy régebbi .xls fájlból harmadik féltől származó eszközök nélkül, az OLE Structured Storage-t kell elemeznie. A Microsoft ezt az IPropertySetStorage COM interfészen keresztül teszi elérhetővé. Íme egy nyers Delphi megvalósítás, amely elkerüli az Excel elindítását:

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;

Programozott kinyerés a HotXLS segítségével

Bár a Windows COM API működik az .xls fájlokkal, nem működik a modern .xlsx fájlokkal (amelyek ZIP archívumok). Továbbá a COM API többplatformos használata (például Linuxon vagy macOS-en a FireMonkey-n keresztül) lehetetlen. A HotXLS komponens legújabb frissítései dedikált egységeket (pl. lxXlsSummary) vezettek be, hogy elszigeteljék és optimalizálják ezen összegző streamek olvasását mindkét formátumban teljesen natív Delphi kóddal.

Egy többplatformos példa

Az XlsReadDocumentSummaryInformation és XlsReadSummaryInformation interfészek használatával gyorsan lekérheti a metaadat karakterláncokat mind az .xls, mind az .xlsx fájlokból anélkül, hogy aggódnia kellene az alapul szolgáló fájlrendszer architektúrája miatt.

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;

Miért fontos a dedikált összegző kinyerése?

Ennek a megközelítésnek az elsődleges előnye a teljesítmény és a memóriabiztonság. A teljes munkafüzet DOM (Document Object Model) példányosításának elkerülésével és csak a docProps/core.xml vagy az OLE tulajdonság streamek elemzésével alkalmazása memórialábnyoma hihetetlenül kicsi marad. Ha 10 000 Excel fájlt indexel egy hálózati megosztáson, mindegyik teljes elemzésének megkísérlése leterheli a memóriát, és órákig tart. A dedikált összegző kinyerése másodpercek alatt elvégzi ugyanezt a feladatot.

Továbbá a streamek natív olvasása biztosítja, hogy alkalmazása háttérszolgáltatásként vagy headless Linux szerveren fusson anélkül, hogy valaha is meghívná az Excel.exe-t—ami kritikus követelmény a modern skálázható architektúrák esetében.

Megjegyzés: Az átfogó Excel elemző és metaadat-kinyerő eszközök a HotXLS VCL komponensben érhetők el.