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

Intervalstil-overlay-diagram for HotXLS, der viser et kolonneformatteringsområde gemt som én record med krævede formatdele i stedet for en million tomme celleobjekter i Delphi
Et kolonne-, række- eller rektangelformat lever én gang som en interval-overlay-post, der gør krav på kun de dele, den ejer. Den effektive stil samles dovent, første gang en celle inden for intervallet faktisk berøres
var
  Sheet: TXLSXWorksheet;
  State: TXLSXCellStyleState;
begin
  Sheet := Workbook.Sheets[1];
  // Stilindekser kommer fra projektmappens stilpuljer, f.eks. fra en celle
  // du allerede har formateret, som du vil have, at rækkevidden skal se ud
  State := BuildStateFromTemplateCell(Sheet.Cells.Item[1, 1]);
  // Formatér kolonner B..D uden at oprette et eneste tomt celleobjekt
  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

Rækkeblokopbevaringsdiagram, der viser HotXLS regnearksceller holdt i faste 256-række-blokke med stabile Delphi handles og række-major-serialisering ind i XLSX deflatestrømmen
Celler sidder i faste 256-række-blokke, der kun allokerer optagne rækker og serialiserer i samme rækkefølge, som bytes forlader processen. Offentlige handles overlever intern reorganisering, så bloklayoutet forbliver usynligt for kaldere

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;
  try
    Workbook.Open('ledger-2026.xlsx');
    // StreamingWrite er som standard True; slå det kun fra, når et nedstrøms-
    // trin kræver, at hele regnearks-XML'en findes før komprimering
    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

StreamingWrite-diagram, der sammenligner perrække deflate streaming i HotXLS med at samle hele regnearks-XML i hukommelsen før komprimering i Delphi
Med StreamingWrite til flyder hver række direkte ind i pakkens deflate-stream, og tophukommelsen følger én række. Slås flaget fra, samles hele regnearks-XML først, hvilket skalerer tophukommelsen med hele arket

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-Delphi-regnearks-komponent-siden opfører de understøttede formater og RAD Studio-versioner