Teknisk artikel

Indstilling af Excel-dokumentegenskaber og metadata i Delphi med HotXLS

Et regneark bærer to identitetslag. Der er cellegitteret, og der er dokumentmetadataene, der kører ved siden af det: titel, forfatter, firma, nøgleord, tidsstempler. Excel viser aldrig det andet lag i gitteret, men det er det lag, Windows Search indekserer, det SharePoint læser for at give et dokument en titel, og det, et journalstyringssystem arkiverer efter. Når en genereret arbejdsbog arver sin Author og Title fra den skabelon, den blev bygget ud fra, registrerer hvert downstream-system skabelondesigneren som forfatteren af fire tusind kundeopgørelser. Metadataene er korrekte ingen steder og konsulteret alle vegne

HotXLS eksponerer dette lag som almindelige egenskaber på arbejdsbogsniveau på begge sine motorer: BIFF-facaden til .xls og OOXML-facaden til .xlsx. Du læser et felt, efter du har åbnet en fil, og du skriver et felt, før du gemmer én. Biblioteket afgør, hvilken fysisk container værdien havner i. Det, der er værd at forstå, før du skriver en generator, er hvilke felter hvert format rent faktisk understøtter, hvor de felter fysisk bor, og den ene spærreregel, der afgør, om en .xlsx overhovedet registrerer nogen metadata

To formater, to lagringsmodeller

Grunden til, at et regnearksbibliotek har brug for to metadata-implementeringer, og grunden til, at halvfærdige værktøjer stempler ét format korrekt og glemmer det andet, er, at .xls og .xlsx holder deres egenskaber på ubeslægtede steder. En BIFF-arbejdsbog skriver dem ind i OLE compound-file-streams, primært i egenskabssættet SummaryInformation, som går forud for selve Excel, sammen med in-stream-posten WRITEACCESS, som navngiver den, der sidst gemte filen. En OOXML-arbejdsbog holder dem som XML-dele inde i zip-pakken, opdelt efter formål: docProps/core.xml holder Dublin Core-felterne (titel, ophavsperson, emne, nøgleord, datoer), og docProps/app.xml holder felterne på applikationsniveau, såsom firma og genererende applikation, ifølge ECMA-376 Part 1

HotXLS flader begge de lagringsmodeller ud til direkte egenskaber på arbejdsbogsobjektet. Du åbner aldrig en egenskabssæt-stream eller redigerer en XML-del i hånden. Du tildeler strenge og datoer til arbejdsbogen, og den korrekte container materialiserer sig for det format, du gemmer i

HotXLS Delphi-diagram, der sammenligner BIFF SummaryInformation-opbevaring med OOXML docProps-dele til Excel dokumentegenskaber
HotXLS flader to urelaterede lagringsmodeller ud til én workbook-egenskabsflade — motoren vælger den fysiske container, når filen gemmes

Stempling af genererede arbejdsbøger fra forretningsjournalen

På XLSX-siden eksponerer TXLSXWorkbook Title, Subject, Author, Keywords, Description, Category, LastModifiedBy, Company, Application og AppVersion som strenge, plus Created og Modified som TDateTime-værdier, hvor nul betyder ikke sat. Reglen, der lukker arvehullet, er én sætning: tildel hvert felt ved hver kørsel, og hent værdierne fra forretningsjournalen i stedet for at stole på, hvad skabelonen tilfældigvis bar med sig

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

    // Overskriv hvert felt: alt, der efterlades urørt, er
    // arvet fra den, der designede skabelonen.
    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;

Feltet Keywords belønner mere eftertanke, end det som regel får. Søgeinfrastruktur indekserer det ordret, Windows Search, SharePoint og de fleste DMS-produkter ens, så en semikolon-separeret konvention, der bærer kontonummeret og perioden, forvandler hver leveret arbejdsbog til en findbar journal uden nogen databaserundtur. Den samme rækkevidde er fangsten. Egenskaber rejser med hver kopi af filen, langt forbi adgangskontrollerne i det system, der skrev dem, så personoplysninger hører ikke hjemme der

Tidsstempelparret bærer semantik, det er værd at fastlægge som politik frem for at overlade til vane. Created bør markere det øjeblik, din pipeline genererede dokumentet, og derefter forblive frosset. Modified er feltet, Excel opdaterer, hver gang en modtager gemmer filen, så en forskel mellem de to efter levering er positivt bevis på, at nogen har redigeret arbejdsbogen nedstrøms, hvilket afgør mere end én tvist om, hvis tal et videresendt regneark rent faktisk indeholder. Én fælde gemmer sig i den usatte tilstand: det er den bogstavelige værdi nul, ikke en undtagelse og ikke en null, så revisionskode må teste for nul eksplicit. Formatér en usat TDateTime uden den beskyttelse, og dine logfiler fyldes med en overbevisende forkert dato i december 1899

DocPropsTouched: arbejdsbogen der sendes uden docProps

Et skrivebeskyttet flag, DocPropsTouched, spærrer for XLSX-egenskabsskriveren. En arbejdsbog, hvor ingen egenskab nogensinde blev tildelt, producerer overhovedet ingen docProps-dele; HotXLS afslår at skrive et tomt metadata-skelet. Adfærden er ryddelig, og den har to konsekvenser, det er værd at designe omkring

Indtagskode på forbrugersiden må ikke antage, at core.xml findes i hver pakke. Et værktøj, der hårdt kræver den, vil afvise helt gyldige minimale filer. Og hvis din compliance-holdning kræver, at hvert udgående dokument bærer mindst en generatoridentitet, bliver det krav til kode frem for en egenskab ved formatet: tildel Application og Author ubetinget i gemmestien, da en urørt arbejdsbog er fuldstændig lovlig under specifikationen, mens den stiltiende krænker din politik

HotXLS Delphi flowdiagram, der viser DocPropsTouched-flaget porte docProps-output i gemte XLSX-projektmapper
DocPropsTouched indgærder XLSX docProps-skriveren — tildél Application og Author ubetinget, når politikken kræver generatoridentitet

Den ældre XLS-flade og Comments-fælden

BIFF-facaden bærer det ældre, mindre feltsæt: Title, Subject, Author, Keywords, Comments, Company og Manager, plus LastSavedBy, et alias for UserName, som skriver WRITEACCESS-posten, Excel viser, når en anden bruger har filen låst

var
  Legacy: IXLSWorkbook;     // reference-tællet grænseflade: intet manuelt 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-post

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

Én navnekollision forårsager tilbagevendende forvirring. Comments-egenskaben på dokumentniveau her er den fritekstbemærkning, der vises i filens egenskabsdialog. Den har intet at gøre med cellekommentarer, som er tegnelagsobjekter knyttet til områder gennem et helt separat API. En kodegennemgang, der accepterer "vi skriver allerede Comments" uden at tjekke, hvilken der menes, har accepteret en påstand om den forkerte funktion, og det sker oftere, end det delte navn skulle antyde. De to deler fire bogstaver og ikke én byte lagring

Læsning af metadata ved indtag, og sonderingshullet

Læsning er symmetrisk. Efter Open kommer de samme egenskaber tilbage udfyldt fra filen, hvilket forvandler en metadata-revision af indkommende arbejdsbøger til en kort løkke

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;

Planlæg omkring én begrænsning, mens du gør det. Der findes ingen egenskaber-only-sondering. GetSheetNames kan liste ark uden at indlæse en arbejdsbog, men at læse Title eller Author betyder et fuldt Open, så metadata-triage på tværs af et stort arkiv betaler den fulde parseomkostning for hver fil. På BIFF-siden kan du skære den omkostning ned for skrivebeskyttede revisioner ved at sætte _DisableGraphics til true, før der åbnes, hvilket springer tegnelaget helt over. Det passer til en løkke, der kun læser egenskaber og cellestatistik, og det er præcis forkert i det øjeblik, den samme instans måtte gemme, fordi det oversprungne tegneindhold ville blive droppet. Når arkstrukturen alene kan forfiltrere sættet, hvor eksport af enkeltark er det oplagte at springe over, skærer de billige teknikker i vores artikel om arklistning og let inspektion ned på, hvor mange filer der når den dyre gennemgang. Og på bulk-stemplingsjob, hvor tusindvis af output skrives snarere end inspiceres, overføres skriveside-gennemstrømningsmønstrene i vores artikel om streaming-skrivninger til batchjob uden ændring, da egenskabstildeling ikke tilføjer noget målbart til gemmetiden

Krydsning af formater og indeslutning af lækken

Egenskaber ruller frem og tilbage rent inden for én enkelt facade: åbn en .xlsx, rediger den, gem den, og sættet kommer tilbage intakt. Krydsning af formater er der, hvor antagelsen om paritet bryder sammen, fordi BIFF- og OOXML-feltsættene ikke stemmer én til én. BIFF har Manager og ingen tidsstempler; OOXML har Category, Description og parret Created/Modified. En konverter, der kopierer blindt, mister alt det, destinationsformatet ikke kan rumme, så mapper felterne eksplicit, og læg mapningen i din konverteringstjekliste ved siden af alt det andet, der ikke overlever turen

HotXLS Delphi feltkort, der viser, hvilke Excel dokumentegenskaber overlever en krydsformatkonvertering mellem XLS og XLSX
En blind krydsformatkopi dropper hvert felt, destinationen ikke kan rumme — afbild BIFF- og OOXML-property sets eksplicit i konverteringstjeklisten

Den læk, skabelonarv åbner, løber den anden vej: information, du aldrig havde til hensigt at sende ud. Forfatternavne, interne projektmærkater parkeret i nøgleord, en kladdetitel, ingen har ryddet op i. Disciplinen med at overskrive alt fra generatoren ovenfor er hele forsvaret, og det er værd at verificere det på den måde, en udenforstående ville, ved at åbne den egenskabsdialog, enhver kunde kan nå, eller ved at udpakke .xlsx'en og læse docProps/core.xml direkte fra pakken. Det, du ser der, er præcis det, hver indekserer nedstrøms ser

Den nedstrøms synlighed er også grunden til, at nogle få felter fortjener mere omhu end resten. Title, Author, Keywords (som viser sig som Tags) og Comments eller Description bærer det meste af indekseringsvægten i SharePoint og Windows Search. En Title, der er ægte distinkt pr. dokument, og som bærer perioden og kontoen, gør mere for findbarhed end noget mappenavngivningsskema oven på det, og det koster én tildeling pr. gemning

Dokumentegenskaber er den billigste professionelle finish, en genereret arbejdsbog kan bære, og den hyppigst leverede defekt, når ingen ejer dem. Begge de egenskabsflader, der er beskrevet her, hører til HotXLS Delphi Component, som skriver dem indfødt til XLS og XLSX uden Excel-automatisering