Techninis straipsnis

Excel dokumento savybių ir darbaknygės metaduomenų nustatymas Delphi su HotXLS

Skaičiuoklė turi du identiteto sluoksnius. Yra langelių tinklelis ir dokumento metaduomenys, keliaujantys kartu su juo: pavadinimas, autorius, įmonė, raktiniai žodžiai, laiko žymos. „Excel“ niekada nerodo šio antrojo sluoksnio tinklelyje, tačiau tai yra būtent tas sluoksnis, kurį indeksuoja „Windows Search“, kurį „SharePoint“ nuskaito dokumento pavadinimui nustatyti ir pagal kurį dokumentų valdymo sistema registruoja failus. Kai sugeneruota darbaknygė paveldi savo autorių ir pavadinimą iš šablono, pagal kurį buvo sukurta, kiekviena tolesnė sistema šablono kūrėją įrašo kaip keturių tūkstančių klientų ataskaitų autorių. Metaduomenys nėra teisingi niekur, tačiau naudojami visur.

HotXLS atskleidžia šį sluoksnį kaip paprastas darbaknygės lygio savybes abiejuose savo varikliuose: BIFF sąsajoje, skirtoje .xls, ir OOXML sąsajoje, skirtoje .xlsx. Atidarę failą nuskaitote lauką, o prieš išsaugodami – įrašote. Biblioteka nusprendžia, kuriame fiziniame konteineryje atsidurs reikšmė. Prieš rašant generatorių verta suprasti, kuriuos laukus kiekvienas formatas iš tikrųjų palaiko, kur tie laukai fiziškai gyvena ir vieną pagrindinę taisyklę, kuri valdo, ar .xlsx failas apskritai įrašo kokius nors metaduomenis.

Du formatai, du saugojimo modeliai

Priežastis, kojų skaičiuoklės bibliotekai reikia dviejų metaduomenų realizacijų ir kodėl pusiau užbaigti įrankiai teisingai užpildo vieną formatą ir pamiršta kitą, yra ta, kad .xls ir .xlsx savo savybes laiko visiškai skirtingose vietose. BIFF darbaknygė jas įrašo į OLE sudėtinio failo srautus, daugiausia į SummaryInformation savybių rinkinį, kuris atsirado dar prieš pačią „Excel“, kartu su vidiniu WRITEACCESS įrašu, nurodančiu, kas paskutinis išsaugojo failą. OOXML darbaknygė jas laiko kaip XML dalis zip pakete, išskirstytas pagal paskirtį: docProps/core.xml laiko Dublin Core laukus (pavadinimą, kūrėją, temą, raktinius žodžius, datas), o docProps/app.xml laiko programos lygio laukus, tokius kaip įmonė ir dokumentą sugeneravusi programa, pagal ECMA-376 Part 1 standartą.

HotXLS suplokština abu šiuos saugojimo modelius į tiesiogines darbaknygės objekto savybes. Jums niekada nereikia atidaryti savybių rinkinio srauto ar rankiniu būdu redaguoti XML dalies. Jūs tiesiog priskiriate eilutes ir datas darbaknygei, o teisingas konteineris sukuriamas priklausomai nuo to, kokiu formatu išsaugote.

Sugeneruotų darbaknygių žymėjimas verslo duomenimis

XLSX pusėje TXLSXWorkbook atskleidžia Title, Subject, Author, Keywords, Description, Category, LastModifiedBy, Company, Application ir AppVersion kaip eilutes, taip pat Created ir Modified kaip TDateTime reikšmes, kur nulis reiškia nenustatytą reikšmę. Taisyklė, padedanti išvengti paveldimo šablono spragos, yra paprasta: priskirkite kiekvieną lauką per kiekvieną paleidimą, paimdami reikšmes iš verslo duomenų, o ne pasitikėdami tuo, ką atsitiktinai turėjo šablonas.

var
  Book: TXLSXWorkbook;
begin
  Book := TXLSXWorkbook.Create;
  try
    if Book.Open('statement-template.xlsx') <> 1 then
      raise Exception.Create('Template not available');

    // Overwrite every field: anything left untouched is
    // inherited from whoever designed the template.
    Book.Title := 'Account Statement 2026-06 / ACME Corp';
    Book.Subject := 'Monthly account statement';
    Book.Author := 'Billing Service 4.2';
    Book.LastModifiedBy := 'Billing Service 4.2';
    Book.Company := 'Northwind Financial';
    Book.Category := 'Customer Delivery';
    Book.Keywords := 'statement;billing;2026-06;acct-10024';
    Book.Description := 'Generated document - manual edits are not retained';
    Book.Created := Now;
    Book.Modified := Now;

    Book.SaveAs('statement-10024.xlsx');
  finally
    Book.Free;
  end;
end;

Laukas Keywords reikalauja daugiau dėmesio nei jam paprastai skiriama. Paieškos infrastruktūra jį indeksuoja pažodžiui (tiek Windows Search, tiek SharePoint, tiek dauguma DMS produktų), todėl kabliataškiais atskirta konvencija, nurodanti paskyros numerį ir laikotarpį, paverčia kiekvieną pristatytą darbaknygę surandamu įrašu be jokių papildomų užklausų duomenų bazėje. Tačiau šis pasiekiamumas turi ir neigiamą pusę. Savybės keliauja su kiekviena failo kopija, toli už jas sukūrusios sistemos prieigos kontrolės ribų, todėl asmens duomenims čia ne vieta.

Laiko žymų pora turi prasmę, kurią verta apibrėžti taisyklėse, o ne palikti savieigai. Created turėtų žymėti momentą, kai jūsų sistema sugeneravo dokumentą, ir išlikti nepakitęs. Lauką Modified „Excel“ atnaujina kiekvieną kartą, kai gavėjas išsaugo failą, žodžiu, šių dviejų reikšmių skirtumas po pristatymo yra aiškus įrodymas, kad kažkas redagavo darbaknygę tolesnėje grandyje, o tai padeda išspręsti ne vieną ginčą dėl to, kieno skaičiai iš tikrųjų yra persiųstoje skaičiuoklėje. Viena spąstų vieta slypi nenustatytoje būsenoje: tai yra pažodinė reikšmė nulis, o ne išimtis ir ne null reikšmė, todėl audito kodas turi aiškiai tikrinti nulinę reikšmę. Suformatavę nenustatytą TDateTime reikšmę be šios apsaugos, savo žurnaluose pamatysite klaidingą 1899 m. gruodžio mėnesio datą.

DocPropsTouched: darbaknygė, siunčiama be docProps

Tik skaitymui skirta žyma, DocPropsTouched, valdo XLSX savybių rašytuvą. Darbaknygė, kurioje nebuvo priskirta jokia savybė, nesukuria jokių docProps dalių; HotXLS tiesiog nerašo tuščio metaduomenų karkaso. Ši elgsena yra tvarkinga ir turi dvi pasekmes, kurias verta numatyti programuojant.

Duomenis priimančios pusės kodas netui daryti prielaidos, kad core.xml egzistuoja kiekviename pakete. Įrankis, kuris to griežtai reikalauja, atmes visiškai galiojančius minimalius failus. O jei jūsų organizacijos taisyklės reikalauja, kad kiekvienas siunčiamas dokumentas turėtų bent generatoriaus identifikatorių, šis reikalavimas tampa kodu, o ne formato savybe: išsaugojimo kelyje besąlygiškai priskirkite Application ir Author reikšmes, nes nepaliesta darbaknygė yra visiškai teisėta pagal specifikaciją, nors tyliai pažeidžia jūsų įmonės taisykles.

Senoji XLS sąsaja ir komentarų spąstai

BIFF sąsaja turi senesnį ir mažesnį laukų rinkinį: Title, Subject, Author, Keywords, Comments, Company ir Manager, taip pat LastSavedBy (UserName alternatyvą), kuri įrašo WRITEACCESS įrašą, kurį „Excel“ rodo, kai kitas vartotojas yra užrakinęs failą.

var
  Legacy: IXLSWorkbook;     // reference-counted interface: no manual Free
begin
  Legacy := TXLSWorkbook.Create;
  if Legacy.Open('archive-1999.xls') <= 0 then
    raise Exception.Create('Cannot open archive file');

  Legacy.Title := 'FY1999 ledger (migrated copy)';
  Legacy.Author := 'Archive Migration Batch';
  Legacy.Company := 'Northwind Financial';
  Legacy.Comments := 'Migrated 2026-06-11; source retained in cold storage';
  Legacy.LastSavedBy := 'migration-svc';   // BIFF WRITEACCESS record

  Legacy.SaveAs('archive-1999-stamped.xls');
end;

Vienas pavadinimų susidūrimas kelia nuolatinę painiavą. Dokumento lygio savybė Comments čia yra laisvos formos pastaba, rodoma failo savybių lange. Ji neturi nieko bendro su langelių komentarais, kurie yra piešimo sluoksnio objektai, pririšti prie diapazonų per visiškai atskirą API. Kodo peržiūra, kurioje sutinkama su teiginiu „mes jau rašome Comments“, nepatikrinus, kuris iš jų turimas omenyje, priima teiginį apie neteisingą funkciją, o tai nutinka dažniau nei leidžia manyti bendras pavadinimas. Šios dvi savybės dalijasi tik pavadinimu ir neturi nė vieno bendro saugojimo baito.

Metaduomenų skaitymas priimant failus ir zondavimo spraga

Skaitymas yra simetriškas. Atlikus Open, tos pačios savybės grąžinamos užpildytos iš failo, o tai paverčia gautų darbaknygių metaduomenų auditą trumpu ciklu.

var
  Book: TXLSXWorkbook;
begin
  Book := TXLSXWorkbook.Create;
  try
    if Book.Open(FileName) = 1 then
    begin
      Writeln(Format('%s | title="%s" author="%s" created=%s',
        [ExtractFileName(FileName), Book.Title, Book.Author,
         FormatDateTime('yyyy-mm-dd', Book.Created)]));
      if Book.Created = 0 then
        Writeln('  no creation date recorded');
    end;
  finally
    Book.Free;
  end;
end;

Planuodami darbus atsižvelkite į vieną apribojimą. Nėra zondavimo funkcijos, skirtos tik savybėms nustatyti. GetSheetNames gali išvardyti lapus neįkeliant darbaknygės, tačiau norint perskaityti Title ar Author, reikia atlikti pilną Open iškvietimą, todėl metaduomenų rūšiavimas dideliame archyve reikalauja pilno kiekvieno failo analizavimo išlaidų. BIFF pusėje šias išlaidas tik skaitymo auditui galite sumažinti nustatę _DisableGraphics į true prieš atidarymą, kas visiškai praleidžia piešimo sluoksnį. Tai tinka ciklui, kuris nuskaito tik savybes ir langelių statistiką, tačiau visiškai netinka, jei tas pats objektas vėliau bus išsaugomas, nes praleistas piešimo turinys būtų prarastas. Kai vien tik lapo struktūra gali iš anksto filtruoti rinkinį (pavyzdžiui, praleidžiant vieno lapo eksportą), pigūs būdai, aprašyti mūsų straipsnyje apie lapų sąrašą ir lengvąjį darbaknygės tikrinimą, sumažina failų, pasiekiančių brangų apdorojimo etapą, skaičių. O atlikus masinius žymėjimo darbus, kai įrašoma tūkstančiai failų, rašymo pusės pralaidumo modeliai, aprašyti mūsų straipsnyje apie srautinį rašymą paketiniams darbams, pritaikomi be jokių pakeitimų, nes savybių priskyrimas nedaro pastebimos įtakos failo išsaugojimo laikui.

Formatų keitimas ir nuotėkio valdymas

Savybės sėkmingai išsaugomos vienoje sąsajoje: atidarykite .xlsx, redaguokite jį, išsaugokite ir savybių rinkinys sugrįš nepažeistas. Tačiau keičiant formatą prielaida apie visišką atitikimą sugriūva, nes BIFF ir OOXML laukų rinkiniai nesutampa vienas su vienu. BIFF turi Manager ir neturi laiko žymų; OOXML turi Category, Description ir Created/Modified porą. Konverteris, kuris aklai kopijuoja, praranda viską, ko negali išlaikyti tikslinis formatas, todėl aiškiai susiekite laukus ir įtraukite šį žemėlapį į savo konvertavimo kontrolinį sąrašą šalia visų kitų dalykų, kurie neišgyvena šio perėjimo.

Nuotėkis, kurį sukelia šablonų paveldėjimas, veikia į kitą pusę: tai informacija, kurios niekada neketinote platinti. Autorių vardai, vidinės projektų žymos raktiniuose žodžiuose, juodraštinis pavadinimas, kurio niekas nepatvirtino. Minėta visų laukų perrašymo taisyklė yra geriausia apsauga. Vertėtų patikrinti failą taip, kaip tai darytų pašalinis asmuo – atidaryti savybių dialogą, kurį gali pasiekti bet kuris klientas, arba išarchyvuoti .xlsx failą ir perskaityti docProps/core.xml tiesiai iš paketo. Tai, ką ten pamatysite, yra būtent tai, ką matys ir visi tolesni paieškos indeksuotojai.

Šis matomumas tolesnėse sistemose taip pat yra priežastis, kodėl keletas laukų nusipelno didesnio rūpesčio nei kiti. Pavadinimas (Title), autorius (Author), raktiniai žodžiai (Keywords, kurie rodomi kaip žymos/Tags) ir komentarai (Comments) arba aprašymas (Description) sudaro didžiąją dalį indeksavimo svorio SharePoint ir Windows Search sistemose. Pavadinimas, kuris yra tikrai unikalus kiekvienam dokumentui (nurodantis laikotarpį ir paskyrą), paieškai suteikia daug daugiau naudos nei bet kokia aplankų pavadinimų schema ir reikalauja tik vieno priskyrimo išsaugojimo metu.

Dokumento savybės yra pigiausias profesionalus sugeneruotos darbaknygės patobulinimas ir dažniausiai pasitaikantis defektas, kai niekas jomis nesirūpina. Abi čia aprašytos savybių sąsajos prikaišo HotXLS Component komponentui, kuris jas įrašo natūraliai XLS ir XLSX failams nenaudojant „Excel“ automatizavimo.