Műszaki cikk

Sorblokkos cellatárolás és folyamatos XLSX-mentések HotXLS-szel

A HotXLS a munkalap-cellákat kompakt 256-soros blokkokban tárolja, a sor-, oszlop- és téglalap-formázást lusta intervallum-átfedéseken keresztül oldja fel cellaobjektumok létrehozása helyett, és mentéskor minden sort egyenesen a csomag deflate-folyamába továbbítja. Együtt ez a három változás dönti el egy nagy munkafüzet memóriaprofilját: a csúcskihasználtság a legnagyobb egyetlen sort követi, nem a teljes munkalap-XML méretét

Az oka annak, hogy ez számít, egy olyan alak, amelyet minden táblázatkezelő-fejlesztő egyszer megismer. Egy felhasználó formázza a teljes oszlopot — egy kattintás, egy millió cella —, és egy naív objektummodell úgy válaszol, hogy egy millió cellaobjektumot foglal le egy számformátum-index tarthatására. A fájlon lévő fájl apró marad, mert az XLSX-formátum ezt egyetlen <col> bejegyzésként fejezi ki. A folyamat egyáltalán nem marad apró

Miért kerül több memóriába egy oszlop formázása, mint a kitöltése?

Mert a formázásnak nincs adata, amely az objektumot indokolná. Egy értékkel rendelkező cellának valahol léteznie kell. Egy cella, amely üres, de stílusozott, csak egy stílusindex hordozására létezik, és millió ilyennek való anyagiasítása a klasszikus módja annak, hogy egy Delphi-táblázatkezelő-alkalmazás címtérből kifogy egy olyan fájlon, amelyet az Excel azonnal megnyit

Az intervallum-stílus-átfedések megszüntetik ennek szükségességét. Egy sor-, oszlop- vagy téglalap-formázási utasítás egyszer tárolódik tartományként plusz a stílusrészekkel, amelyeket hozzájárul, és lustán oldódik fel, amikor egy cellát abban a tartományban ténylegesen elérnek. Az átfedések túlélik a strukturális szerkesztéseket — egy sor beszúrása egy formázott blokkba az intervallumot mozgatja, nem újraépíti — és oda-vissza kompakt oszlop-, sor- és csak-stílus cellabejegyzésként mennek, ami pontosan úgy, ahogy az Excel írja őket

Intervallum stílusátfedési diagram HotXLS-hez: egy oszlopformázási tartomány egyetlen rekordként tárolva igényelt formátumrészekkel, millió üres cellaobjektum helyett Delphi-ben
Egy oszlop-, sor- vagy téglalap-formátum egyszer él, intervallum-fedő rekordként, amely csak az általa birtokolt részeket követeli. A tényleges stílus lustán áll össze, amikor egy tartományon belüli cellát először ténylegesen megérintenek
var
  Sheet: TXLSXWorksheet;
  State: TXLSXCellStyleState;
begin
  Sheet := Workbook.Sheets[1];
  // A stílusindexek a munkafüzet stíluskészleteiből származnak, pl. egy cellából,
  // amelyet már úgy formázott, ahogy a tartománynak kinéznie kell
  State := BuildStateFromTemplateCell(Sheet.Cells.Item[1, 1]);
  // A B..D oszlopok formázása anélkül, hogy egyetlen üres cellaobjektum jönne létre
  Sheet.StyleOverlays.Add(1, 2, MaxRowIndex, 4,
    [xfpNumberFormat, xfpAlignment], State);
end;

A TXLSXFormatParts az a halmaz, amely eldönti, mit járul hozzá egy átfedés: xfpFont, xfpFill, xfpBorder, xfpNumberFormat, xfpAlignment és xfpProtection. Csak azoknak a részeknek a megnevezése teszi, hogy az átfedések értelmesen rétegződjenek — egy számformátumot szolgáltató oszlop-átfedés nem küzd egy kitöltést szolgáltató sor-átfedéssel, mert egyik sem követeli a másik részét

Mit ad a 256-soros blokk?

Lokalitást. A cellák 256-soros blokkokban vannak tartva stabil nyilvános fogantyúkkal, sor-fő sorrendben szerializálva, így egy munkalap írása memóriában abban a sorrendben halad, ahogy a bájtokat ki fogja bocsátani, nem pedig mutatókat követve a halom körül. A stabil fogantyúk az API-felületnél számítanak: egy fogantyú, amelyet a hívó birtokol, érvényes marad a blokk-elrendezés által végzett belső átszervezésen keresztül, ami teszi, hogy a kompakt reprezentáció megvalósítási részlet maradjon, ne törő-változás

Sorblokk-tárolási diagram: HotXLS munkalacellák rögzített 256 soros blokkokban tartva stabil Delphi handleekkel és sorfő szerializálással az XLSX deflate streambe
A cellák rögzített 256 soros blokkokban ülnek, amelyek csak a foglalt sorokat allokálják, és abban a sorrendben szerializálódnak, ahogy a bájtok elhagyják a folyamatot. A nyilvános handelek túlélik a belső átrendezést, így a blokkelrendezés láthatatlan marad a hívók számára

A stíluskészlet-kompakció mellette fut. Minden mentés előtt a betűtípusok, kitöltések, keretek, számformátumok, igazítások és védelmek, amelyekre egyetlen cella sem hivatkozik, eldobásra kerülnek. Az hosszú életű munkafüzetek úgy halmozzák fel a hivatkozás nélküli stílusrekordokat, ahogy a hosszú életű dokumentumok halmozzák a fel nem használt stílusokat, és egy olyan munkafüzet, amelyet egy felhasználó egy órán át szerkesztett, több százat vihet bele egy olyan fájlba, amelyet senki sem fog valaha olvasni

Sor-folyamatos mentés, és amikor nem alkalmazandó

A StreamingWrite engedélyezésével — ez az alapértelmezés — minden munkalapsor egyenesen a csomag deflate-folyamába íródik. A másik lehetőség, amelyet a jelző kikapcsol, először felépíti a teljes munkalap-XML-t, és utána komprimálja, így a csúcsmemória a teljes lappal skálázódik. A folyamatos írás skálázódással egy sorral teszi

A megosztott karakterláncok és kiegészítő részek ugyanezt a fegyelmet követik egy újrahasználható UTF-8 szerializálón keresztül, amely egyszerre egy bejegyzést bocsát ki, a csúcsmemóriát a legnagyobb egyetlen bejegyzéshez mérve, nem a teljes részhez. Ez lefedi a megosztott karakterlánctáblát és a pivot-rekordokat, amelyek egy széles analitikus munkafüzetnél gyakran nagyobbak, mint bármely egyéni munkalap

var
  Workbook: TXLSXWorkbook;
begin
  Workbook := TXLSXWorkbook.Create;
  try
    Workbook.Open('ledger-2026.xlsx');
    // A StreamingWrite alaphelyzetben True; csak akkor kapcsolja ki, ha egy downstream
    // lépés megköveteli, hogy a teljes munkalap XML a tömörítés előtt létezzen
    Workbook.StreamingWrite := True;
    Workbook.SaveAs('ledger-2026-out.xlsx');
  finally
    Workbook.Free;
  end;
end;

Hagyjuk bekapcsolva, hacsak nincs konkrét okunk kikapcsolni. A nem folyamatos út azokhoz az esetekhez létezik, amikor a futószalagon valami másnak szüksége van az összeállított XML-re, és alapértelmezetten fizetni érte egy olyan esetet fizetni, amelyet a legtöbb alkalmazás sosem ér el

Hogyan mondjuk meg, hogy az átfedéseket valóban használják?

A cellaszámot figyeljük, nem a memóriagrafikont. Ha egy munkalap egy hihető számú fizikai celláról jelent széleskörű formázás alkalmazása után, az átfedések teszik a dolgukat. Ha a szám a formázott tartomány méretével ugrik, valami a kódúton anyagiasította a cellákat — általában egy ciklus, amely minden cellát kiolvas a tartományban, hogy ellenőrizze a stílusát, ami cellánkénti feloldást kényszerít ki, és az egész elrendezést megveri

StreamingWrite diagram: soronkénti deflate streamelés a HotXLS-ben szemben a teljes munkalap XML memóriában összeállításával tömörítés előtt Delphi-ben
StreamingWrite bekapcsolásával minden sor egyenesen a csomag deflate streamjébe áramlik, és a csúcs-memória egy sort követ. A jelző kikapcsolása előbb összerakja a teljes munkalap XML-t, ami a csúcs-memóriát a teljes lappal skáláztatja

Oldjunk fel egy stílust, amikor egyetlen cella effektív formátumára van szükség. Ne oldjunk fel egy stílust egy millió cellára, hogy kiderüljük, hogy az oszlop rendelkezik számformátummal; kérdezzük meg az átfedést. Ugyanez a szabály vonatkozik az írásra: rendeljünk értékeket azokhoz a cellákhoz, amelyek értékkel rendelkeznek, és hagyjuk, hogy a formázás intervallum maradjon

Hova megy a maradék memória

Ha a cellák és a stílusok kompaktok, a következő legnagyobb fogyasztók egy nagy munkafüzeten a megosztott karakterlánctábla és azok a műhold-részek, amelyeket a fájl hordoz — pivot-gyorsítótárak, rajzok, megőrzött XML azokból a részekből, amelyeket az objektummodell nem modellez. Ezeknek megvannak a saját stratégiáik, és az őszinte válasz az, hogy egyetlen beállítás sem oldja meg mindet egyszerre

Ha a szűk keresztmetszet a megnyitás, nem a mentés, a szelektív betöltés a kar: a csak-metaadat és szelektív munkalapbetöltés átjárása egy munkafüzet olvasását tárgyalja anélkül, hogy fizetnénk azokért a munkalapokért, amelyeket nem fogunk érinteni. Nagyon nagy fájlok olvasási útján lévő áteresztőképességhez lásd a párhuzamos XLSX-elemzés és a memóriafoglaló jegyzeteit, és olyan kizárólag kimeneti munkaterhelésekhez, amelyeknek egyáltalán nincs szükségük objektummodellre, a folyamatos írás szerver-köteg-feladatokhoz általában jobb választás, mint bármennyi finomhangolás itt

A HotXLS natív Delphi és C++Builder kódból olvassa és írja az XLS és XLSX fájlokat Excel-telepítés és OLE-automatizáció nélkül, ami teszi, hogy ezek a memóriajellemzők egyáltalán megfigyelhetők és szabályozhatók — a HotXLS táblázatkezelő komponens oldal felsorolja a támogatott formátumokat és RAD Studio verziókat