Khi xử lý các lô bảng tính Excel lớn trong một đường ống tự động, bạn hiếm khi muốn tải toàn bộ tài liệu vào bộ nhớ chỉ để tìm hiểu xem nó là gì. Thông thường, siêu dữ liệu được nhúng trong tệp (tác giả, tiêu đề, ngày tạo và các thuộc tính tùy chỉnh) là đủ để định tuyến, lập chỉ mục hoặc từ chối tài liệu. Trong thế giới Microsoft Office, siêu dữ liệu này được gọi là Thông tin tóm tắt tài liệu.
Việc trích xuất thông tin này một cách nguyên bản trong Delphi mà không dựa vào tự động hóa OLE (yêu cầu Excel phải được cài đặt trên máy chủ) đòi hỏi phải phân tích trực tiếp cấu trúc tệp cơ bản. Trong bài viết này, chúng ta sẽ xem xét cách thức hoạt động của các bản tóm tắt tài liệu trong tệp Excel và cách trích xuất chúng một cách hiệu quả bằng cách sử dụng phân tích luồng thô.
Hiểu về các luồng siêu dữ liệu Excel
Về mặt lịch sử, các tệp Excel cũ (.xls) được lưu trữ theo định dạng OLE Compound Document, hoạt động như các hệ thống tệp thu nhỏ chứa các luồng và vùng lưu trữ. Siêu dữ liệu được lưu trữ trong hai luồng cụ thể:
SummaryInformation: Chứa các thuộc tính tiêu chuẩn như Tiêu đề, Chủ đề, Tác giả, Từ khóa và Số bản sửa đổi.DocumentSummaryInformation: Chứa các thuộc tính mở rộng như Công ty, Người quản lý và các thuộc tính tùy chỉnh do người dùng xác định.
Các tệp Excel hiện đại (.xlsx) sử dụng định dạng Office Open XML (OOXML), đây là một cấu trúc XML được nén. Siêu dữ liệu ở đây được đặt tại docProps/core.xml, docProps/app.xml và docProps/custom.xml. Một thành phần phân tích cú pháp Delphi mạnh mẽ phải xử lý liền mạch cả hai cấu trúc bên trong trong khi cung cấp một API thống nhất cho nhà phát triển.
Phân tích OLE Compound Documents trong Delphi
Để đọc SummaryInformation từ tệp `.xls` cũ mà không cần công cụ của bên thứ ba, bạn cần phân tích OLE Structured Storage. Microsoft cung cấp điều này thông qua giao diện COM IPropertySetStorage. Dưới đây là cách triển khai Delphi thô giúp tránh khởi động 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;
Trích xuất có lập trình với HotXLS
Mặc dù Windows COM API hoạt động với các tệp `.xls`, nhưng nó không hoạt động với các tệp `.xlsx` hiện đại (là tài liệu lưu trữ ZIP). Hơn nữa, việc sử dụng COM API đa nền tảng (ví dụ: trên Linux hoặc macOS thông qua FireMonkey) là không thể. Các bản cập nhật gần đây cho thành phần HotXLS đã giới thiệu các đơn vị chuyên dụng (ví dụ: lxXlsSummary) để cô lập và tối ưu hóa việc đọc các luồng tóm tắt này trên cả hai định dạng một cách hoàn toàn nguyên bản bằng mã Delphi.
Một ví dụ đa nền tảng
Sử dụng các giao diện XlsReadDocumentSummaryInformation và XlsReadSummaryInformation, bạn có thể nhanh chóng lấy các chuỗi siêu dữ liệu từ cả `.xls` và `.xlsx` mà không cần lo lắng về kiến trúc hệ thống tệp cơ bản.
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;
Tại sao trích xuất tóm tắt chuyên dụng lại quan trọng
Lợi ích chính của phương pháp này là hiệu suất và an toàn bộ nhớ. Bằng cách tránh khởi tạo toàn bộ DOM (Mô hình đối tượng tài liệu) của sổ làm việc và chỉ phân tích cú pháp docProps/core.xml hoặc các luồng thuộc tính OLE, dung lượng ứng dụng của bạn vẫn cực kỳ nhỏ. Nếu bạn đang lập chỉ mục 10.000 tệp Excel trên một chia sẻ mạng, việc cố gắng phân tích cú pháp đầy đủ từng tệp sẽ làm quá tải bộ nhớ của bạn và mất hàng giờ. Trích xuất tóm tắt chuyên dụng hoàn thành nhiệm vụ tương tự chỉ trong vài giây.
Hơn nữa, việc đọc các luồng một cách nguyên bản đảm bảo ứng dụng của bạn có thể chạy dưới dạng dịch vụ nền hoặc trên máy chủ Linux không có giao diện người dùng mà không cần gọi đến Excel.exe, một yêu cầu quan trọng đối với các kiến trúc hiện đại có thể mở rộng.
Lưu ý: Các công cụ phân tích cú pháp Excel và trích xuất siêu dữ liệu toàn diện có sẵn trong HotXLS VCL Component.