Technical Article

Delphi'de Excel Dosyalarından Belge Özet Bilgilerini Çıkarma

Büyük Excel elektronik tablo (spreadsheet) yığınlarını otomatik bir boru hattında (pipeline) işlerken, bir belgenin ne olduğunu anlamak için nadiren tüm belgeyi belleğe yüklemek istersiniz. Genellikle, dosyanın içine gömülü olan meta veriler (yazar, başlık, oluşturma tarihi ve özel özellikler) belgeyi yönlendirmek, indekslemek veya reddetmek için yeterlidir. Microsoft Office dünyasında bu meta veriler Belge Özet Bilgileri (Document Summary Information) olarak bilinir.

OLE otomasyonuna güvenmeden (ki bu, Excel'in ana makinede kurulu olmasını gerektirir) bu bilgileri Delphi'de yerel (natively) olarak çıkarmak, temeldeki dosya yapısını doğrudan ayrıştırmayı gerektirir. Bu makalede, belge özetlerinin Excel dosyalarında nasıl çalıştığına ve ham akış ayrıştırması (raw stream parsing) kullanarak bunları verimli bir şekilde nasıl çıkaracağımıza bakacağız.

Excel Meta Veri Akışlarını Anlamak

Tarihsel olarak, daha eski Excel dosyaları (.xls) OLE Bileşik Belge (OLE Compound Document) formatlarında depolanır ve etkili bir şekilde akışlar (streams) ile depolar (storages) içeren mini dosya sistemleri olarak hareket ederler. Meta veriler iki özel akışta barındırılır:

  • SummaryInformation: Başlık, Konu, Yazar, Anahtar Kelimeler ve Revizyon Numarası gibi standart özellikleri içerir.
  • DocumentSummaryInformation: Şirket, Yönetici ve kullanıcının tanımladığı özel özellikler gibi genişletilmiş özellikleri içerir.

Modern Excel dosyaları (.xlsx), sıkıştırılmış (zipped) bir XML yapısı olan Office Açık XML (OOXML) formatını kullanır. Buradaki meta veriler docProps/core.xml, docProps/app.xml ve docProps/custom.xml dosyalarında bulunur. Sağlam bir Delphi ayrıştırma bileşeni, geliştiriciye birleşik bir API sunarken her iki iç yapıyı da sorunsuz bir şekilde ele almalıdır.

Delphi'de OLE Bileşik Belgeleri Ayrıştırma

Eski bir .xls dosyasından SummaryInformation'ı üçüncü taraf araçlar olmadan okumak için, OLE Yapılandırılmış Depolamayı (OLE Structured Storage) ayrıştırmanız gerekir. Microsoft bunu IPropertySetStorage COM arayüzü (interface) aracılığıyla sunar. İşte Excel'i çalıştırmaktan kaçınan ham bir Delphi uygulaması:

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;

HotXLS ile Programatik Çıkarım

Windows COM API .xls dosyaları için çalışırken, modern .xlsx dosyaları (ki bunlar ZIP arşivleridir) için çalışmaz. Dahası, COM API'sini çapraz platformda (örneğin, FireMonkey aracılığıyla Linux veya macOS'ta) kullanmak imkansızdır. HotXLS bileşenine yapılan son güncellemeler, bu özet akışların her iki formatta da tamamen yerel olarak Delphi kodunda okunmasını yalıtmak ve optimize etmek için özel birimler (örneğin, lxXlsSummary) tanıttı.

Çapraz Platform Bir Örnek

XlsReadDocumentSummaryInformation ve XlsReadSummaryInformation arayüzlerini kullanarak, temeldeki dosya sistemi mimarisi hakkında endişelenmeden hem .xls hem de .xlsx dosyalarından meta veri dizelerini (strings) hızlı bir şekilde alabilirsiniz.

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;

Özel Özet Çıkarımı Neden Önemlidir?

Bu yaklaşımın birincil faydası performans ve bellek güvenliğidir. Tam çalışma kitabı (workbook) DOM'unu (Belge Nesne Modeli) örneklendirmekten kaçınarak ve yalnızca docProps/core.xml veya OLE özellik akışlarını ayrıştırarak, uygulamanızın bellek ayak izi inanılmaz derecede küçük kalır. Bir ağ paylaşımında (network share) 10.000 Excel dosyasını indeksliyorsanız, her birini tam olarak ayrıştırmaya çalışmak belleğinizi yoracak ve saatler sürecektir. Özel özet çıkarımı ise aynı görevi saniyeler içinde tamamlar.

Dahası, akışları yerel olarak okumak, uygulamanızın bir arka plan hizmeti olarak veya gözetimsiz (headless) bir Linux sunucusunda Excel.exe'yi hiç çağırmadan çalışabilmesini sağlar; bu, modern ölçeklenebilir mimariler için kritik bir gereksinimdir.

Not: Kapsamlı Excel ayrıştırma ve meta veri çıkarma araçları HotXLS VCL Component bileşeninde mevcuttur.