Όταν επεξεργάζεστε μεγάλες παρτίδες λογιστικών φύλλων Excel σε μια αυτοματοποιημένη ροή (pipeline), σπάνια θέλετε να φορτώσετε ολόκληρο το έγγραφο στη μνήμη μόνο και μόνο για να καταλάβετε τι είναι. Συχνά, τα μεταδεδομένα (metadata) που είναι ενσωματωμένα στο αρχείο, όπως συγγραφέας, τίτλος, ημερομηνία δημιουργίας και προσαρμοσμένες ιδιότητες, επαρκούν για τη δρομολόγηση, την ευρετηρίαση ή την απόρριψη του εγγράφου. Στον κόσμο του Microsoft Office, αυτά τα μεταδεδομένα είναι γνωστά ως Πληροφορίες Σύνοψης Εγγράφου (Document Summary Information).
Η εξαγωγή αυτών των πληροφοριών εγγενώς στο Delphi χωρίς την εξάρτηση από τον αυτοματισμό OLE (ο οποίος απαιτεί την εγκατάσταση του Excel στο μηχάνημα φιλοξενίας) απαιτεί την άμεση ανάλυση της υποκείμενης δομής του αρχείου. Σε αυτό το άρθρο, θα εξετάσουμε πώς λειτουργούν οι συνόψεις εγγράφων στα αρχεία Excel και πώς να τις εξάγουμε αποτελεσματικά χρησιμοποιώντας ακατέργαστη ανάλυση ροής (raw stream parsing).
Κατανόηση των Ροών Μεταδεδομένων του Excel
Ιστορικά, τα παλαιότερα αρχεία Excel (.xls) αποθηκεύονται σε μορφές OLE Compound Document, λειτουργώντας ουσιαστικά ως μίνι συστήματα αρχείων που περιέχουν ροές (streams) και χώρους αποθήκευσης (storages). Τα μεταδεδομένα στεγάζονται σε δύο συγκεκριμένες ροές:
SummaryInformation: Περιέχει τυπικές ιδιότητες όπως Τίτλο (Title), Θέμα (Subject), Συγγραφέα (Author), Λέξεις-κλειδιά (Keywords) και Αριθμό Αναθεώρησης (Revision Number).DocumentSummaryInformation: Περιέχει εκτεταμένες ιδιότητες όπως Εταιρεία (Company), Διευθυντή (Manager) και προσαρμοσμένες ιδιότητες καθορισμένες από τον χρήστη.
Τα σύγχρονα αρχεία Excel (.xlsx) χρησιμοποιούν τη μορφή Office Open XML (OOXML), η οποία είναι μια συμπιεσμένη (zipped) δομή 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 σε πολλαπλές πλατφόρμες (cross-platform, π.χ., σε Linux ή macOS μέσω FireMonkey) είναι αδύνατη. Πρόσφατες ενημερώσεις του στοιχείου HotXLS εισήγαγαν αποκλειστικές μονάδες (units) (π.χ., lxXlsSummary) για την απομόνωση και τη βελτιστοποίηση της ανάγνωσης αυτών των ροών σύνοψης και στις δύο μορφές, εντελώς εγγενώς σε κώδικα Delphi.
Ένα Παράδειγμα Cross-Platform
Χρησιμοποιώντας τις διεπαφές 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 (Μοντέλου Αντικειμένου Εγγράφου) του βιβλίου εργασίας και αναλύοντας μόνο το docProps/core.xml ή τις ροές ιδιοτήτων OLE, το αποτύπωμα της εφαρμογής σας παραμένει απίστευτα μικρό. Εάν ευρετηριάζετε 10.000 αρχεία Excel σε ένα κοινόχρηστο δίκτυο (network share), η προσπάθεια πλήρους ανάλυσης καθενός από αυτά θα εξαντλήσει τη μνήμη σας και θα διαρκέσει ώρες. Η αποκλειστική εξαγωγή σύνοψης ολοκληρώνει την ίδια εργασία σε δευτερόλεπτα.
Επιπλέον, η εγγενής ανάγνωση των ροών διασφαλίζει ότι η εφαρμογή σας μπορεί να εκτελεστεί ως υπηρεσία παρασκηνίου (background service) ή σε διακομιστή χωρίς οθόνη (headless server) σε Linux χωρίς ποτέ να γίνει κλήση του Excel.exe, μια κρίσιμη απαίτηση για τις σύγχρονες κλιμακούμενες αρχιτεκτονικές.
Σημείωση: Ολοκληρωμένα εργαλεία ανάλυσης Excel και εξαγωγής μεταδεδομένων είναι διαθέσιμα στο HotXLS VCL Component.