HotXLS kan één werkblad herschrijven binnen een bestaand XLSX-pakket zonder de rest van het bestand te parsen of opnieuw te comprimeren. TXLSDirectWriter.BeginPatch opent een bronpakket, kopieert elk item behalve het doelwerkblad letterlijk over met zijn gecomprimeerde bytes, en laat u dat ene werkblad opnieuw opstellen via de gewone aanroepen AddSheet, AddRow en Write*. Grafieken, draaitabelcaches, thema's, stijlen en gedeelde strings worden helemaal nooit gedecomprimeerd
De workflow die dit oplost, komt voor bij rapportage en data-verversing. Een werkmap komt binnen van een businessteam met draaitabellen, slicers, voorwaardelijke opmaak en een decennium aan opgebouwde opmaak. Elke nacht moet één datawerkblad worden vervangen door verse cijfers. De hele werkmap laden en opnieuw opslaan kost minuten per bestand en, belangrijker nog, brengt de getrouwheid van functies die de laad-engine moet reconstrueren in gevaar. Patchen omzeilt beide problemen door niets aan te raken wat het niet hoeft aan te raken
Waarom is het kopiëren van gecomprimeerde bytes het interessante deel?
Een zip-item dat op gecomprimeerd niveau wordt gekopieerd, kost een streamkopie. Datzelfde item via een normaal schrijfpad kost een inflate op de weg naar binnen en een deflate op de weg naar buiten, en deflate is de dure helft. Bij een werkmap met een grote draaitabelcache en enkele tientallen ingesloten afbeeldingen is dat verschil het verschil tussen een patch die klaar is in de tijd die het kost om het nieuwe werkblad te schrijven, en een patch die het grootste deel van zijn tijd besteedt aan het opnieuw comprimeren van bytes die hij nooit heeft bekeken
HotXLS gebruikt hiervoor CopyCompressedFrom, dat de gecomprimeerde bytes van het bronitem rechtstreeks in het doelarchief schrijft. Wanneer een item niet op die manier kan worden gekopieerd, omdat het een andere compressiemethode of zwakke versleuteling gebruikt, valt de writer terug op een gedecomprimeerde streamkopie in plaats van te falen. Directorymarkeringsitems worden overgeslagen, aangezien de writer zijn eigen items produceert
Ter plekke vervangen, of naar een nieuw bestand schrijven
Twee overloads dekken de twee vormen die deze taak kan aannemen. De ter-plekke-vorm zet het resultaat klaar in een tijdelijk bestand naast het origineel, sluit de bronhandle, en verwijdert en hernoemt dan, zodat een crash halverwege het schrijven het origineel intact laat. De vorm met een expliciet doel laat de bron ongemoeid en kan ofwel een werkblad vervangen ofwel een nieuw werkblad toevoegen:
var
W: TXLSDirectWriter;
begin
W := TXLSDirectWriter.Create;
try
W.BeginPatch('monthly-dashboard.xlsx', 'Data'); // ter plekke
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;
De invoegvariant neemt een bron- en een doelpad plus InsertSheet:
// Bron blijft ongemoeid; doel krijgt een extra werkblad genaamd Extra
W.BeginPatch('template.xlsx', 'output.xlsx', 'Extra', True);
W.AddSheet('Extra');
W.AddRow(1);
W.WriteString(1, 'appended by the nightly job');
W.Close;
Invoegen is het deel dat echte boekhoudkundige chirurgie vereist. De writer parst het werkbladregister in xl/workbook.xml en de relatiekaart die elk werkblad aan zijn onderdeel bindt, en kiest dan het eerstvolgende vrije onderdeelnummer, werkblad-ID en relatie-ID. Relatietypen volgen de conventies van het bronpakket, dus het patchen van een strikte ISO 29500-werkmap genereert strikte relatietypen en het patchen van een transitionele werkmap genereert transitionele typen
Wat de patch bewust laat vallen en beperkt
De berekeningsketen wordt in beide modi weggelaten. In vervangmodus beschrijven de items ervan cellen in een werkblad dat niet meer in die vorm bestaat; in invoegmodus maakt de verschuiving van de werkbladindex de keten ronduit ongeldig. Excel bouwt de keten opnieuw op bij de volgende herberekening, dus deze weglaten is correct in plaats van verliesgevend. Het onderdeel wordt uit de kopie weggelaten, en het bijbehorende relatie-item en content-type-override worden chirurgisch verwijderd
Twee authoring-semantieken veranderen binnen een patch, en beide volgen uit hetzelfde principe: de patch mag onderdelen die het niet herschreef niet verstoren. Strings worden inline in het werkblad geschreven in plaats van aan de gedeelde-stringtabel te worden toegevoegd, omdat de brontabel ongewijzigd wordt overgezet. En StyleIndex verwijst naar items in de cellXfs van het bronpakket, niet naar een stijltabel die de writer opbouwt. Dat betekent dat u kunt verwijzen naar opmaak die de originele werkmap al definieert, wat meestal precies is wat een data-ververing wil, maar het betekent ook dat u moet weten welke index welke opmaak draagt
// Binnen een patch indexeert StyleIndex de cellXfs van het BRONpakket.
// Een datum heeft een expliciete index nodig die daar naar een datumnotatie wijst:
W.WriteDateTime(3, EncodeDate(2026, 8, 22), DateStyleIndexFromTemplate);
// De stijlvrije WriteDateTime-overload wordt in patchmodus geweigerd,
// omdat deze uitgaat van de eigen stijltabel van de writer, die een patch
// nooit aanmaakt
Zes authoring-toegangspunten zijn afgeschermd: het toevoegen van tabellen, grafieken, afbeeldingen, opmerkingen, gedefinieerde namen en celstijlen werpt allemaal een uitzondering in patchmodus, met een tweede vangnet bij het sluiten dat faalt als een van hun tellers niet nul is. Elk van die functies zou het bewerken vereisen van onderdelen die de patch letterlijk kopieert, en een half bewerkt pakket is erger dan een geweigerde bewerking. Er mag precies één werkblad per bewerking worden gepatcht
Wanneer patchen en wanneer laden
Patchen is het juiste gereedschap wanneer de werkmap groot is, de wijziging beperkt is tot één werkblad, en de rest van het bestand bit voor bit intact moet blijven. Het is het verkeerde gereedschap wanneer de wijziging meerdere werkbladen omvat, wanneer nieuwe opmaak of nieuwe objecten nodig zijn, of wanneer het bestand klein genoeg is dat een normale laad- en opslagactie niets kost. Voor bulkgeneratie vanaf nul blijft het streamingpad beschreven in de streaming direct writer de betere keuze, en dat deelt dezelfde AddRow- en Write*-API, dus overstappen tussen de twee is mechanisch
Manipulatie op werkbladniveau binnen een geladen werkmap, wanneer u wel het volledige objectmodel wilt, wordt behandeld in werkbladen dupliceren in XLSX-pakketten. En als de reden dat u een patch overweegt is dat verwerking van de hele werkmap traag is geworden, zijn de metingen en het geheugengedrag in prestaties van grote werkmappen het waard om te lezen voordat u een aanpak kiest
Verifiëren dat een patch echt deed wat u dacht
Drie controles vangen bijna elke fout op. Bevestig dat de onderdelen waarvan u verwachtte dat ze behouden zouden blijven, nog steeds in het archief staan, dat xl/calcChain.xml verdwenen is, en dat het opnieuw openen van het bestand via TXLSXWorkbook het verwachte aantal werkbladen rapporteert, ongewijzigd bij een vervanging en met één verhoogd bij een invoeging. Het gepatchte werkblad terug inlezen en een paar waarden en formules vergelijken, sluit de lus
Eén implementatiedetail uit de ontwikkeling van deze functie is het herhalen waard, omdat het iedereen kan bijten die vergelijkbare code op zip-niveau schrijft. Werkbladonderdeelnamen worden op prefix gematcht, en een off-by-one in de prefixlengte betekent dat het predicaat nooit matcht, waardoor een nieuw geschreven onderdeel botst met een bestaande naam en lezers die het laatste item met een gegeven naam nemen, stilzwijgend het verkeerde werkblad kiezen. Als een patch de inhoud van twee werkbladen lijkt om te wisselen, kijk dan eerst naar naammatching voordat u naar de XML kijkt
Ter-plekke-patchen, streaming schrijven en het volledige werkmapobjectmodel worden geleverd in dezelfde bibliotheek voor Delphi en C++Builder; de functielijst staat op de HotXLS Delphi-spreadsheetcomponentpagina