Ett kalkylblad bär två lager av identitet. Det finns rutnätet av celler, och det finns dokumentmetadatan som åker bredvid: titel, författare, företag, nyckelord, tidsstämplarna. Excel visar aldrig det andra lagret i rutnätet, ändå är det lagret Windows Search indexerar, det som SharePoint läser för att namnge ett dokument, och det som ett dokumenthanteringssystem arkiverar efter. När en genererad arbetsbok ärver sin författare och titel från mallen den byggdes av, registrerar varje nedströmssystem malldesignern som författare till fyra tusen kundbesked. Metadatan är korrekt ingenstans och konsulteras överallt
HotXLS lyfter fram det här lagret som vanliga egenskaper på arbetsboksnivå i båda sina motorer: BIFF-fasaden för .xls och OOXML-fasaden för .xlsx. Du läser ett fält efter att ha öppnat en fil och du skriver ett fält innan du sparar en. Biblioteket avgör vilken fysisk behållare värdet landar i. Vad som är värt att förstå innan du skriver en generator är vilka fält varje format faktiskt stöder, var de fälten fysiskt bor, och den enda grindregel som styr om en .xlsx över huvud taget registrerar någon metadata
Två format, två lagringsmodeller
Skälet till att ett kalkylbladsbibliotek behöver två metadataimplementationer, och skälet till att halvfärdiga verktyg stämplar ett format korrekt och glömmer det andra, är att .xls och .xlsx håller sina egenskaper på orelaterade ställen. En BIFF-arbetsbok skriver dem i strömmar i den sammansatta OLE-filen, främst egenskapsuppsättningen SummaryInformation som är äldre än Excel självt, jämte posten WRITEACCESS i strömmen som namnger den som senast sparade filen. En OOXML-arbetsbok håller dem som XML-delar inuti zip-paketet, uppdelade efter syfte: docProps/core.xml håller Dublin Core-fälten (titel, skapare, ämne, nyckelord, datum) och docProps/app.xml håller fälten på applikationsnivå såsom företag och genererande applikation, enligt ECMA-376 del 1
HotXLS plattar ut båda de lagringsmodellerna till direkta egenskaper på arbetsboksobjektet. Du öppnar aldrig en egenskapsuppsättningsström eller redigerar en XML-del för hand. Du tilldelar strängar och datum till arbetsboken, och rätt behållare materialiseras för vilket format du än sparar
Att stämpla genererade arbetsböcker från affärsposten
På XLSX-sidan exponerar TXLSXWorkbook egenskaperna Title, Subject, Author, Keywords, Description, Category, LastModifiedBy, Company, Application och AppVersion som strängar, plus Created och Modified som TDateTime-värden där noll betyder osatt. Regeln som täpper till arvshålet är en enda mening: tilldela varje fält vid varje körning, och hämta värdena från affärsposten istället för att lita på vad mallen råkade bära
var
Book: TXLSXWorkbook;
begin
Book := TXLSXWorkbook.Create;
try
if Book.Open('statement-template.xlsx') <> 1 then
raise Exception.Create('Template not available');
// Skriv över varje fält: allt som lämnas orört ärvs
// från den som designade mallen.
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;
Fältet Keywords ger mer tillbaka än den eftertanke det brukar få. Sökinfrastruktur indexerar det ordagrant, Windows Search, SharePoint och de flesta DMS-produkter lika, så en semikolonseparerad konvention som bär kontonummer och period gör varje levererad arbetsbok till en sökbar post utan en enda databasrundtur. Samma räckvidd är haken. Egenskaper följer med varje kopia av filen, långt bortom åtkomstkontrollerna i systemet som skrev dem, så personuppgifter hör inte hemma där
Tidsstämpelparet bär en semantik värd att fastställa i policy snarare än att lämna åt vanan. Created bör markera stunden din pipeline genererade dokumentet och sedan stå frusen. Modified är fältet Excel uppdaterar närhelst en mottagare sparar filen, så en avvikelse mellan de två efter leverans är positivt bevis för att någon redigerat arbetsboken nedströms, vilket avgör mer än en tvist om vems siffror ett vidarebefordrat kalkylblad egentligen håller. En fälla gömmer sig i det osatta tillståndet: det är det literala värdet noll, inte ett undantag och inte en null, så granskningskod måste testa mot noll uttryckligen. Formatera ett osatt TDateTime utan den skyddsvakten så fylls dina loggar med ett självsäkert felaktigt datum i december 1899
DocPropsTouched: arbetsboken som levereras utan docProps
En skrivskyddad flagga, DocPropsTouched, grindar XLSX-egenskapsskrivaren. En arbetsbok där ingen egenskap någonsin tilldelats framställer inga docProps-delar alls; HotXLS avstår från att skriva ett tomt metadataskelett. Beteendet är städat, och det har två följder värda att designa runt
Mottagningskod på konsumentsidan får inte anta att core.xml finns i varje paket. Ett verktyg som hårt kräver det avvisar fullt giltiga minimala filer. Och om din efterlevnadshållning kräver att varje utgående dokument bär åtminstone en generatoridentitet blir det kravet kod snarare än en egenskap hos formatet: tilldela Application och Author villkorslöst i spar-vägen, eftersom en orörd arbetsbok är helt laglig enligt specifikationen samtidigt som den tyst bryter mot din policy
Den äldre XLS-ytan och Comments-fällan
BIFF-fasaden bär den äldre, mindre fältuppsättningen: Title, Subject, Author, Keywords, Comments, Company och Manager, plus LastSavedBy, ett alias för UserName, som skriver den WRITEACCESS-post Excel visar när en annan användare har filen låst
var
Legacy: IXLSWorkbook; // referensräknat gränssnitt: ingen manuell 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;
En namnkrock orsakar återkommande förvirring. Egenskapen Comments på dokumentnivå här är den fritextanmärkning som visas i filens egenskapsdialog. Den har ingenting med cellkommentarer att göra, som är objekt i ritlagret fästa vid områden genom ett helt separat API. En kodgranskning som accepterar ”vi skriver redan Comments” utan att kontrollera vilken som avses har accepterat ett påstående om fel funktion, och det händer oftare än det delade namnet antyder. De två delar fyra bokstäver och inte en enda byte lagring
Att läsa metadata vid mottagning, och sonderingsluckan
Läsningen är symmetrisk. Efter Open kommer samma egenskaper tillbaka ifyllda från filen, vilket gör en metadatagranskning av inkommande arbetsböcker till en kort loop
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;
Planera runt en begränsning medan du gör det. Det finns ingen sondering av enbart egenskaper. GetSheetNames kan lista blad utan att läsa in en arbetsbok, men att läsa Title eller Author innebär ett fullständigt Open, så metadatasortering över ett stort arkiv betalar den fulla tolkningskostnaden för varje fil. På BIFF-sidan kan du trimma den kostnaden för skrivskyddade granskningar genom att sätta _DisableGraphics till sant före öppning, vilket hoppar över ritlagret rakt av. Det passar en loop som bara läser egenskaper och cellstatistik, och det är precis fel i samma stund som instansen kan komma att spara, eftersom det överhoppade ritinnehållet då skulle släppas. När bladstrukturen ensam kan förfiltrera mängden, med enbladsexporter som det uppenbara att hoppa över, minskar de billiga teknikerna i vår artikel om bladlistning och lättviktig inspektion hur många filer som når det dyra passet. Och i massstämplingsjobb, där tusentals utdata skrivs snarare än inspekteras, gäller genomströmningsmönstren på skrivsidan i vår artikel om strömmande skrivning för batchjobb oförändrat, eftersom egenskapstilldelning inte lägger något mätbart till spartiden
Att korsa format och begränsa läckaget
Egenskaper klarar rundturen rent inom en och samma fasad: öppna en .xlsx, redigera den, spara den, och uppsättningen kommer tillbaka intakt. Att korsa format är där antagandet om paritet brister, eftersom BIFF:s och OOXML:s fältuppsättningar inte går ihop en mot en. BIFF har Manager och inga tidsstämplar; OOXML har Category, Description och paret Created/Modified. En konverterare som kopierar blint tappar allt målformatet inte kan hålla, så mappa fälten uttryckligen och lägg mappningen i din konverteringschecklista bredvid allt annat som inte överlever resan
Läckaget som mallarv öppnar går åt andra hållet: information du aldrig menade att skicka ut. Författarnamn, interna projektbeteckningar parkerade i nyckelord, en utkasttitel ingen godkänt. Disciplinen att skriva över allt från generatorn ovan är hela försvaret, och den är värd att verifiera så som en utomstående skulle göra, genom att öppna egenskapsdialogen vilken kund som helst når eller genom att packa upp .xlsx-filen och läsa docProps/core.xml rakt ur paketet. Det du ser där är exakt vad varje indexerare nedströms ser
Den nedströmssynligheten är också skälet till att några fält förtjänar mer omsorg än resten. Title, Author, Keywords (som dyker upp som Taggar) och Comments eller Description bär den mesta indexeringstyngden i SharePoint och Windows Search. En titel som är genuint särskiljande per dokument, och som bär perioden och kontot, gör mer för sökbarheten än något mappnamnschema staplat ovanpå den, och den kostar en tilldelning per sparande
Dokumentegenskaper är den billigaste professionella finish en genererad arbetsbok kan bära, och den vanligaste levererade defekten när ingen äger dem. Båda egenskapsytorna som beskrivs här tillhör HotXLS Delphi Component, som skriver dem inbyggt för XLS och XLSX utan Excel-automation