Teknisk artikel

Række-blok-celle-lagring og streamet XLSX-gemning i HotXLS

HotXLS lagrer regnearks-celler i kompakte 256-række-blokke, resolver række-, kolonne- og rektangel-formatering gennem dovne interval-overlays frem for at oprette celle-objekter, og streamer hver række direkte ind i pakkens deflate-strøm ved gemning. Tilsammen beslutter disse tre ændringer hukommelses-profilen af en stor projektmappe: top-forbrug følger den største enkelte række frem for størrelsen af den komplette regnearks-XML

Grunden til at det betyder noget, er en form, enhver regnearks-udvikler møder før eller siden. En bruger formaterer en hel kolonne — ét klik, én million celler — og en naiv objekt-model svarer ved at allokere en million celle-objekter til at holde ét talformat-indeks. Filen på disk forbliver lille, fordi XLSX-formatet udtrykker det som en enkelt <col>-post. Processen forbliver slet ikke lille

Hvorfor koster formatering af en kolonne mere hukommelse end at udfylde den?

Fordi formatering ikke har nogen data til at retfærdiggøre objektet. En celle med en værdi er nødt til at eksistere et sted. En celle, der er tom men styled, eksisterer kun for at bære et stil-indeks, og at materialisere millioner af dem er den klassiske måde, en Delphi-regnearks-applikation løber tør for adresse-rum på en fil, Excel åbner øjeblikkeligt

Interval-stil-overlays fjerner behovet. En række-, kolonne- eller rektangel-formaterings-instruktion lagres én gang som et interval plus de stil-dele, den bidrager med, og resolver dovent, når en celle i det interval faktisk tilgås. Overlays overlever strukturelle redigeringer — at indsætte en række inde i en formateret blok flytter intervallet frem for at genopbygge det — og de rundturs som kompakte kolonne-, række- og kun-stil-celle-poster, hvilket er præcis, hvordan Excel skriver dem

var
  Sheet: TXLSXWorksheet;
  State: TXLSXCellStyleState;
begin
  Sheet := Workbook.Sheets[1];
  // Style indexes come from the workbook style pools, e.g. from a cell
  // you have already formatted the way you want the range to look
  State := BuildStateFromTemplateCell(Sheet.Cells.Item[1, 1]);
  // Format columns B..D without creating a single empty cell object
  Sheet.StyleOverlays.Add(1, 2, MaxRowIndex, 4,
    [xfpNumberFormat, xfpAlignment], State);
end;

TXLSXFormatParts er det sæt, der beslutter, hvad et overlay bidrager med: xfpFont, xfpFill, xfpBorder, xfpNumberFormat, xfpAlignment og xfpProtection. Kun at navngive de dele, du mener, er det, der lader overlays lagde sig fornuftigt — et kolonne-overlay, der leverer et talformat, kæmper ikke med et række-overlay, der leverer et fyld, fordi ingen af dem gør krav på den andens del

Hvad giver 256-række-blokken dig?

Lokalitet. Cellen holdes i blokke af 256 rækker med stabile offentlige handles, serialiseret row-major, så skrivning af et regneark går hukommelsen efter i den rækkefølge, den vil emitte byte, frem for at forfølge pointere på tværs af heapen. Stabile handles betyder noget for API-fladen: et handle, en kalder holder, forbliver gyldigt på tværs af den interne reorganisering, blok-layoutet udfører, hvilket er det, der gør den kompakte repræsentation til en implementations-detalje frem for en breaking change

Stil-pool-kompaktion kører ved siden af. Før hver gemning dropes skrifttyper, fyld, kanter, talformater, justeringer og beskyttelser, som ingen celle refererer til. Langlivede projektmapper akkumulerer urefererede stil-poster på samme måde, som langlivede dokumenter akkumulerer ubrugte stile, og en projektmappe, der har været redigeret af en bruger i en time, kan bære hundreder af dem ind i en fil, ingen nogensinde vil læse dem fra

Række-streamet gemning, og hvornår den ikke gælder

Med StreamingWrite aktiveret — standarden — skrives hver regnearks-række direkte ind i pakkens deflate-strøm. Alternativet, som er det, flaget slår fra, bygger først den komplette regnearks-XML og komprimerer den bagefter, så top-hukommelse skalerer med hele arket. Streaming gør, at den skalerer med én række

Shared strings og auxiliære dele følger samme disciplin gennem én genbrugelig UTF-8-serialisering, der emitterer poster én ad gangen og afgrænser top-hukommelse ved den største enkelte post frem for hele delen. Det dækker shared string-tabellen og pivot-poster, som på et bredt analytisk regneark ofte er større end noget enkelt regneark

var
  Workbook: TXLSXWorkbook;
begin
  Workbook := TXLSXWorkbook.Create(nil);
  try
    Workbook.Open('ledger-2026.xlsx');
    // StreamingWrite defaults to True; turn it off only when a downstream
    // step requires the whole worksheet XML to exist before compression
    Workbook.StreamingWrite := True;
    Workbook.SaveAs('ledger-2026-out.xlsx');
  finally
    Workbook.Free;
  end;
end;

Lad den være tændt, medmindre du har en konkret grund til ikke at. Den ikke-streamede sti eksisterer for de tilfælde, hvor noget andet i pipelinen har brug for den samlede XML, og at betale for den som standard er at betale for et tilfælde, de fleste applikationer aldrig rammer

Hvordan ser du, om overlays reelt bruges?

Se på celle-tællingen, ikke hukommelses-grafen. Rapporterer et regneark et plausibelt antal fysiske celler, efter at du har anvendt bred formatering, gør overlays deres arbejde. Springer tællingen med størrelsen af det formaterede interval, har noget i kode-stien materialiseret cellerne — normalt en løkke, der læser hver celle i intervallet for at tjekke dens stil, hvilket gennemtvinger resolution én celle ad gangen og besejrer hele arrangementet

Resolver en stil, når du har brug for én celles effektive format. Resolver ikke en stil for en million celler for at finde ud af, at kolonnen har et talformat; spørg overlayet. Samme regel gælder for skrivning: tildel værdier til de celler, der har værdier, og lad formatering forblive et interval

Hvor den resterende hukommelse går hen

Når celler og stile først er kompakte, er de næststørste forbrugere på en stor projektmappe shared string-tabellen og de satellit-dele, filen bærer — pivot-caches, tegninger, bevaret XML fra dele, objekt-modellen ikke modellerer. De har deres egne strategier, og det ærlige svar er, at ingen enkelt indstilling løser dem alle på én gang

Er din flaskehals åbning frem for gemning, er selektiv indlæsning armen: gennemgangen af kun-metadata og selektiv regnearks-indlæsning dækker at læse en projektmappe uden at betale for de ark, du ikke vil røre. For læse-sti-gennemstrømning på meget store filer, se noterne om parallel XLSX-parsing og hukommelses-allokatoren, og til rene output-arbejdsbyrder, der aldrig har brug for en objekt-model overhovedet, er streaming-skrivning til server-batch-jobs normalt et bedre fit end nogen mængde tuning her

HotXLS læser og skriver XLS og XLSX fra native Delphi- og C++Builder-kode uden Excel-installation og uden OLE-automation, hvilket er det, der gør disse hukommelses-karakteristika observerbare og kontrollerbare i første omgang — HotXLS-regnearks-komponent-siden opfører de understøttede formater og RAD Studio-versioner