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

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;

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

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(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;

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

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