A HotXLS képes újraírni egy munkalapot egy meglévő XLSX-csomagon belül anélkül, hogy a fájl többi részét elemezné vagy újratömörítené. A TXLSDirectWriter.BeginPatch megnyit egy forráscsomagot, a célmunkalap kivételével minden bejegyzést tömörített bájtjaival szó szerint átmásol, és lehetővé teszi, hogy azt az egyetlen munkalapot a szokásos AddSheet, AddRow és Write* hívásokkal újraírd. A diagramok, pivot gyorsítótárak, témák, stílusok és megosztott stringek egyáltalán nem kerülnek kitömörítésre
Az ezáltal megoldott munkafolyamat jelentéskészítésben és adatfrissítésben jelenik meg. Egy munkafüzet érkezik egy üzleti csapattól, amely pivot táblázatokat, szeletelőket, feltételes formázásokat és egy évtizednyi felhalmozott formázást hordoz. Minden éjjel egy adatlapot friss számokra kell cserélni. A teljes munkafüzet betöltése és újramentése fájlonként perceket vesz igénybe, és ami még fontosabb, kockáztatja a hűséget azoknál a funkcióknál, amelyeket a betöltőmotornak újra kell építenie. A javítás mindkét problémát megkerüli azzal, hogy nem nyúl ahhoz, amihez nem kell
Miért érdekes rész a tömörített bájtok másolása?
Egy zip-bejegyzés, amelyet tömörített szinten másolunk, egyetlen stream-másolásba kerül. Ugyanaz a bejegyzés, ha egy normál írási útvonalon megy keresztül, egy kitömörítésbe kerül befelé menet és egy tömörítésbe kifelé menet, a tömörítés pedig a drágább fele. Egy nagy pivot gyorsítótárral és néhány tucat beágyazott képpel rendelkező munkafüzet esetében ez a különbség dönt afelől, hogy a javítás annyi idő alatt fejeződik-e be, amennyi az új munkalap megírásához kell, vagy az ideje nagy részét olyan bájtok újratömörítésével tölti, amelyeket sosem vizsgált meg
A HotXLS ehhez a CopyCompressedFrom-ot használja, amely a forrásbejegyzés tömörített bájtjait közvetlenül a célarchívumba írja. Ha egy bejegyzést nem lehet így másolni, mert eltérő tömörítési módszert vagy gyenge titkosítást használ, az író kitömörített stream-másolásra vált vissza, ahelyett hogy elbukna. A könyvtárjelölő bejegyzéseket kihagyja, mivel az író sajátokat állít elő
Csere a helyén, vagy írás új fájlba
Két túlterhelt változat fedi le a feladat két formáját. A helyben végzett forma az eredeti mellé egy ideiglenes fájlba helyezi az eredményt, lezárja a forrás handle-jét, majd töröl és átnevez, így egy írás közbeni összeomlás érintetlenül hagyja az eredetit. Az explicit célt megadó forma érintetlenül hagyja a forrást, és vagy lecserél egy munkalapot, vagy hozzáfűz egy újat:
var
W: TXLSDirectWriter;
begin
W := TXLSDirectWriter.Create;
try
W.BeginPatch('monthly-dashboard.xlsx', 'Data'); // in place
W.AddSheet('Data');
W.AddRow(1);
W.WriteString(1, 'Region');
W.WriteString(2, 'Revenue');
W.AddRow(2);
W.WriteString(1, 'North');
W.WriteNumber(2, 184320.55);
W.AddRow(3);
W.WriteFormula(1, '=SUM(B2:B2)');
W.Close;
finally
W.Free;
end;
end;
A beszúró változat egy forrás- és egy célútvonalat vár, plusz az InsertSheet-et:
// A forrás érintetlen marad; a cél egy Extra nevű extra munkalapot kap
W.BeginPatch('template.xlsx', 'output.xlsx', 'Extra', True);
W.AddSheet('Extra');
W.AddRow(1);
W.WriteString(1, 'appended by the nightly job');
W.Close;
A beszúrás az a rész, amely valódi könyvelési sebészetet igényel. Az író elemzi a munkalapregisztert az xl/workbook.xml-ben és a kapcsolattérképet, amely minden munkalapot a részéhez köt, majd kiválasztja a következő szabad részszámot, munkalap-azonosítót és kapcsolatazonosítót. A kapcsolattípusok a forráscsomag konvencióit követik, így egy strict ISO 29500 munkafüzet javítása strict kapcsolattípusokat állít elő, egy átmenetié pedig átmeneti típusokat
Mit dob el és korlátoz szándékosan a javítás?
A számítási láncot mindkét mód eldobja. Csere módban a bejegyzései olyan cellákat írnak le, amelyek már nem léteznek abban a formában egy munkalapon; beszúrás módban a munkalapindex-eltolódás egyenesen érvényteleníti azt. Az Excel a következő újraszámoláskor újraépíti a láncot, így az eldobása helyes, nem veszteséges. A rész kimarad a másolatból, a kapcsolatbejegyzését és a tartalomtípus-felülbírálását pedig sebészi pontossággal távolítja el
Két írási szemantika változik meg egy javításon belül, és mindkettő ugyanabból az elvből következik: a javítás nem zavarhatja meg azokat a részeket, amelyeket nem írt újra. A stringek soron belülre íródnak a munkalapba ahelyett, hogy a megosztott string táblához adódnának hozzá, mivel a forrástábla érintetlenül kerül át. A StyleIndex pedig a forráscsomag cellXfs-ében lévő bejegyzésekre hivatkozik, nem az író által épített stílustáblára. Ez azt jelenti, hogy hivatkozhatsz az eredeti munkafüzet által már definiált formátumokra, ami általában pontosan az, amit egy adatfrissítés akar, de azt is jelenti, hogy tudnod kell, melyik index melyik formátumot hordozza
// Egy javításon belül a StyleIndex a FORRÁS csomag cellXfs-ét indexeli.
// Egy dátumhoz explicit index kell, amely ott egy dátumformátumra képez:
W.WriteDateTime(3, EncodeDate(2026, 8, 22), DateStyleIndexFromTemplate);
// A stílus nélküli WriteDateTime túlterhelt változatot javítás módban elutasítja,
// mert az feltételezi az író saját stílustábláját, amelyet egy javítás
// soha nem hoz létre
Hat írási belépési pont van kapuzva: táblázatok, diagramok, képek, megjegyzések, elnevezett tartományok és cellastílusok hozzáadása egyaránt kivételt dob javítás módban, egy második biztonsági hálóval a lezáráskor, amely elbukik, ha bármelyik számlálójuk nem nulla. Ezen funkciók bármelyike olyan részek szerkesztését igényelné, amelyeket a javítás szó szerint másol, egy félig szerkesztett csomag pedig rosszabb, mint egy elutasított művelet. Műveletenként pontosan egy munkalap javítható
Mikor javíts, és mikor tölts be?
A javítás a helyes eszköz akkor, ha a munkafüzet nagy, a változás egyetlen munkalapra korlátozódik, és a fájl többi részének bitre pontosan túl kell élnie. Rossz eszköz akkor, ha a változás több munkalapot érint, ha új formázásra vagy új objektumokra van szükség, vagy ha a fájl elég kicsi ahhoz, hogy egy normál betöltés és mentés semmibe se kerüljön. Ha a nulláról történő tömeges generálásról van szó, a streamelő közvetlen íróban leírt streamelő útvonal jobb választás marad, és ugyanazt az AddRow és Write* API-t osztja meg, így a kettő közötti váltás mechanikus
A munkalapszintű manipulációt egy betöltött munkafüzeten belül, ha valóban a teljes objektummodellt szeretnéd, a munkalapok duplikálása XLSX-csomagokban ismerteti. Ha pedig azért fontolgatsz egy javítást, mert a teljes munkafüzet feldolgozása lassúvá vált, a nagy munkafüzetek teljesítménye cikkben szereplő mérések és memóriaviselkedés érdemes elolvasni, mielőtt megközelítést választanál
Annak ellenőrzése, hogy a javítás valóban azt tette, amit gondolsz
Három ellenőrzés szinte minden hibát elkap. Erősítsd meg, hogy azok a részek, amelyeknek szerinted túl kellett élniük, még mindig az archívumban vannak, hogy az xl/calcChain.xml eltűnt, és hogy a fájl TXLSXWorkbook-on keresztüli újramegnyitása a várt munkalapszámot jelenti, cserénél változatlanul, beszúrásnál eggyel megnövelve. A javított munkalap visszaolvasása és néhány érték, illetve képlet összehasonlítása zárja le a kört
Egy implementációs részlet e funkció fejlesztéséből érdemes megismételni, mert bárkit megharaphat, aki hasonló zip-szintű kódot ír. A munkalaprész-nevek előtag szerint illeszkednek, és egy eggyel elcsúszott előtaghossz azt jelenti, hogy a predikátum soha nem illeszkedik, így egy újonnan írt rész ütközik egy már létező névvel, és azok az olvasók, amelyek egy adott néven az utolsó bejegyzést veszik, csendben a rossz munkalapot választják. Ha egy javítás úgy tűnik, mintha felcserélte volna két munkalap tartalmát, előbb nézd meg a névillesztést, csak utána az XML-t
A helyben végzett javítás, a streamelő írás és a teljes munkafüzet-objektummodell ugyanabban a könyvtárban érkezik Delphihez és C++Builderhez; a funkciólista a HotXLS Delphi táblázatkezelő-komponens oldalán található