Коли ви обробляєте великі партії електронних таблиць Excel в автоматизованому конвеєрі, вам рідко хочеться завантажувати весь документ у пам'ять лише для того, щоб зрозуміти, що це таке. Часто метаданих, вбудованих у файл: автора, назви, дати створення та користувацьких властивостей, достатньо для маршрутизації, індексування або відхилення документа. У світі Microsoft Office ці метадані відомі як Підсумкова інформація про документ (Document Summary Information).
Вилучення цієї інформації нативно у Delphi без покладання на OLE-автоматизацію (яка вимагає встановленого Excel на хост-машині) вимагає безпосереднього аналізу базової структури файлу. У цій статті ми розглянемо, як працюють підсумки документів у файлах Excel і як їх ефективно вилучати за допомогою синтаксичного аналізу необроблених потоків.
Розуміння потоків метаданих Excel
Історично старі файли Excel (.xls) зберігаються у форматах OLE Compound Document, фактично діючи як міні-файлові системи, що містять потоки та сховища. Метадані розміщені у двох спеціальних потоках:
SummaryInformation: Містить стандартні властивості, такі як заголовок (Title), тема (Subject), автор (Author), ключові слова (Keywords) та номер ревізії (Revision Number).DocumentSummaryInformation: Містить розширені властивості, такі як компанія (Company), менеджер (Manager) та власні користувацькі властивості.
Сучасні файли Excel (.xlsx) використовують формат Office Open XML (OOXML), який є заархівованою структурою XML. Метадані тут розташовані у файлах docProps/core.xml, docProps/app.xml та docProps/custom.xml. Надійний компонент синтаксичного аналізу для Delphi повинен безперешкодно обробляти обидві внутрішні структури, надаючи розробнику уніфікований API.
Синтаксичний аналіз документів OLE Compound у Delphi
Щоб прочитати SummaryInformation із застарілого файлу `.xls` без інструментів сторонніх розробників, вам потрібно проаналізувати сховище OLE Structured Storage. Microsoft надає це через COM-інтерфейс IPropertySetStorage. Ось базова реалізація на Delphi, яка дозволяє уникнути запуску 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;
Програмне вилучення за допомогою HotXLS
Хоча Windows COM API працює для файлів `.xls`, він не працює для сучасних файлів `.xlsx` (які є ZIP-архівами). Крім того, використання COM API як кросплатформного рішення (наприклад, на Linux або macOS через FireMonkey) є неможливим. Нещодавні оновлення компонента HotXLS представили спеціальні модулі (наприклад, lxXlsSummary) для ізоляції та оптимізації читання цих підсумкових потоків в обох форматах повністю нативно у коді Delphi.
Кросплатформний приклад
Використовуючи інтерфейси XlsReadDocumentSummaryInformation та XlsReadSummaryInformation, ви можете швидко отримати рядки метаданих як з файлів `.xls`, так і з файлів `.xlsx`, не турбуючись про базову архітектуру файлової системи.
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;
Чому важливе спеціалізоване вилучення підсумків
Основною перевагою цього підходу є продуктивність та безпека пам'яті. Уникаючи створення повного DOM (Document Object Model) робочої книги та аналізуючи лише docProps/core.xml або потоки властивостей OLE, слід вашого додатка залишається неймовірно малим. Якщо ви індексуєте 10 000 файлів Excel через мережевий ресурс, спроба повністю проаналізувати кожен з них виснажить вашу пам'ять і триватиме годинами. Спеціалізоване вилучення підсумків виконує те саме завдання за лічені секунди.
Крім того, нативне читання потоків гарантує, що ваш додаток зможе працювати як фонова служба або на сервері Linux без графічного інтерфейсу (headless) без жодного виклику Excel.exe, що є критичною вимогою для сучасних масштабованих архітектур.
Примітка: Комплексні інструменти для аналізу Excel та вилучення метаданих доступні у компоненті HotXLS VCL.