Teknisk artikkel

Patche ett regneark i en stor XLSX fra Delphi

HotXLS kan skrive om ett regneark inni en eksisterende XLSX-pakke uten å analysere eller komprimere resten av filen på nytt. TXLSDirectWriter.BeginPatch åpner en kildepakke, kopierer hver oppføring bortsett fra målarket over med sine komprimerte byte helt uendret, og lar deg forfatte det ene arket på nytt gjennom de vanlige kallene AddSheet, AddRow og Write*. Diagrammer, pivot-cacher, temaer, stiler og delte strenger blir aldri dekomprimert i det hele tatt

Arbeidsflyten dette løser, dukker opp i rapportering og dataoppfriskning. En arbeidsbok kommer fra et forretningsteam og bærer pivottabeller, dataskiver, betingede formater og et tiår med opparbeidet formatering. Hver natt må ett datablad erstattes med ferske tall. Å laste inn og lagre hele arbeidsboken på nytt koster minutter per fil, og enda viktigere, risikerer troskap på funksjoner innlastingsmotoren må rekonstruere. Patching omgår begge problemene ved ikke å røre det den ikke trenger å røre

Hvorfor er kopiering av komprimerte byte den interessante delen?

En zip-oppføring som kopieres på komprimert nivå, koster en strømkopi. Den samme oppføringen ført gjennom en normal skrivebane koster en inflate på vei inn og en deflate på vei ut, og deflate er den dyre halvparten. På en arbeidsbok med en stor pivot-cache og noen dusin innebygde bilder er den forskjellen forskjellen mellom en patch som blir ferdig på tiden det tar å skrive det nye arket, og en som bruker mesteparten av tiden sin på å komprimere byte den aldri undersøkte, på nytt

HotXLS bruker CopyCompressedFrom til dette, som skriver kildeoppføringens komprimerte byte rett inn i målarkivet. Når en oppføring ikke kan kopieres på den måten, fordi den bruker en annen komprimeringsmetode eller svak kryptering, faller skriveren tilbake til en dekomprimert strømkopi i stedet for å feile. Katalogmarkør-oppføringer hoppes over, siden skriveren produserer sine egne

Erstatte på stedet, eller skrive til en ny fil

To overbelastede varianter dekker de to formene denne oppgaven kan ta. På-stedet-formen mellomlagrer resultatet i en midlertidig fil ved siden av originalen, lukker kildehåndtaket, og sletter og gir deretter nytt navn, slik at en krasj midt i skrivingen lar originalen være urørt. Den eksplisitt-mål-formen lar kilden være urørt og kan enten erstatte et ark eller legge til et nytt:

var
  W: TXLSDirectWriter;
begin
  W := TXLSDirectWriter.Create;
  try
    W.BeginPatch('monthly-dashboard.xlsx', 'Data');   // på stedet
    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;

Innsettingsvarianten tar imot en kilde og en målsti pluss InsertSheet:

  // Kilden forblir urørt; målet får et ekstra regneark kalt 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;

Innsetting er delen som krever ekte kirurgisk bokføring. Skriveren analyserer arkregisteret i xl/workbook.xml og relasjonskartet som binder hvert ark til sin del, og velger deretter det neste ledige delnummeret, arkidentifikatoren og relasjonsidentifikatoren. Relasjonstyper følger konvensjonene til kildepakken, så patching av en strict ISO 29500-arbeidsbok produserer strenge relasjonstyper, og patching av en overgangsvis produserer overgangsvise typer

Hva patchen bevisst dropper og begrenser

Beregningskjeden forkastes i begge moduser. I erstatningsmodus beskriver oppføringene dens celler i et ark som ikke lenger finnes i den formen; i innsettingsmodus gjør arkindeksforskyvningen den ugyldig med det samme. Excel bygger kjeden på nytt ved neste omregning, så å droppe den er korrekt og ikke et tap. Delen utelates fra kopien, og dens relasjonsoppføring og innholdstype-overstyring fjernes kirurgisk

To forfattersemantikker endres inni en patch, og begge følger av det samme prinsippet: patchen må ikke forstyrre deler den ikke skrev om. Strenger skrives inline inn i arket i stedet for å bli lagt til den delte strengtabellen, fordi kildetabellen krysser over urørt. Og StyleIndex refererer til oppføringer i kildepakkens cellXfs, ikke til en stiltabell skriveren bygger. Det betyr at du kan referere til formater den originale arbeidsboken allerede definerer, noe som som regel er nøyaktig hva en dataoppfriskning ønsker, men det betyr også at du må vite hvilken indeks som bærer hvilket format

// Inni en patch indekserer StyleIndex KILDE-pakkens cellXfs.
// En dato trenger en eksplisitt indeks som kartlegges til et datoformat der:
W.WriteDateTime(3, EncodeDate(2026, 8, 22), DateStyleIndexFromTemplate);

// Den stilfrie WriteDateTime-overbelastningen avvises i patch-modus,
// fordi den forutsetter skriverens egen stiltabell, noe en patch
// aldri oppretter

Seks forfatter-inngangspunkter er sperret: å legge til tabeller, diagrammer, bilder, kommentarer, definerte navn og cellestiler utløser alle et unntak i patch-modus, med et sekundært sikkerhetsnett ved lukketidspunktet som feiler hvis noen av deres tellere er ulik null. Hver av disse funksjonene ville kreve redigering av deler patchen kopierer ordrett, og en halvredigert pakke er verre enn en avvist operasjon. Nøyaktig ett ark kan patches per operasjon

Når du skal patche, og når du skal laste inn

Patching er det riktige verktøyet når arbeidsboken er stor, endringen er avgrenset til ett ark, og resten av filen må overleve bit for bit. Det er det gale verktøyet når endringen spenner over flere ark, når ny formatering eller nye objekter trengs, eller når filen er liten nok til at en vanlig innlasting og lagring ikke koster noe. For massegenerering fra bunnen av forblir strømningsbanen beskrevet i den strømmende direkteskriveren det bedre valget, og den deler det samme AddRow- og Write*-API-et, så å bevege seg mellom de to er mekanisk

Manipulasjon på arknivå inni en innlastet arbeidsbok, når du faktisk vil ha hele objektmodellen, er dekket i duplisering av regneark i XLSX-pakker. Og hvis grunnen til at du vurderer en patch, er at behandling av hele arbeidsboken har blitt treg, er målingene og minneoppførselen i ytelse for store arbeidsbøker verdt å lese før du velger en tilnærming

Verifisere at en patch faktisk gjorde det du tror

Tre sjekker fanger opp nesten hver eneste feil. Bekreft at delene du forventet skulle overleve, fremdeles er i arkivet, at xl/calcChain.xml er borte, og at gjenåpning av filen gjennom TXLSXWorkbook rapporterer det arkantallet du forventer, uendret for en erstatning og økt med én for en innsetting. Å lese det patchede arket tilbake og sammenligne noen få verdier og formler lukker sirkelen

Én implementasjonsdetalj fra utviklingen av denne funksjonen fortjener å gjentas, fordi den kan bite alle som skriver lignende kode på zip-nivå. Regneark-delnavn matches etter prefiks, og en av-med-én-feil i prefikslengden betyr at predikatet aldri treffer, slik at en nyskrevet del kolliderer med et eksisterende navn, og lesere som tar den siste oppføringen med et gitt navn, plukker stille det gale arket. Hvis en patch ser ut til å bytte om innholdet i to ark, se på navnematching før du ser på XML-en

På-stedet-patching, strømmende skriving og hele arbeidsbokobjektmodellen leveres i det samme biblioteket for Delphi og C++Builder; funksjonslisten finnes på HotXLS Delphi regnearkkomponentsiden