Techninis straipsnis

Vieno darbalapio pataisymas didelėje XLSX byloje iš Delphi

HotXLS gali perrašyti vieną darbalapį esamame XLSX pakete neanalizuodama ir iš naujo nesuspausdama likusios failo dalies. TXLSDirectWriter.BeginPatch atidaro šaltinio paketą, nukopijuoja kiekvieną įrašą, išskyrus tikslinį lapą, su jo suspaustais baitais pažodžiui, ir leidžia iš naujo sukurti tą vieną lapą per įprastus AddSheet, AddRow ir Write* iškvietimus. Diagramos, suvestinių lentelių (pivot) talpyklos, temos, stiliai ir bendrinamos eilutės apskritai niekada nedekompresuojamos

Šis darbo srautas sprendžia problemą, kylančią ataskaitų teikime ir duomenų atnaujinime. Darbaknygė atkeliauja iš verslo komandos, nešdama suvestines lenteles, pjaustykles, sąlyginį formatavimą ir dešimtmečiu kauptą formatavimą. Kiekvieną naktį vieną duomenų lapą reikia pakeisti naujais skaičiais. Visos darbaknygės įkėlimas ir pakartotinis išsaugojimas kainuoja kelias minutes vienam failui ir, kas svarbiau, rizikuoja tikslumu tų funkcijų, kurias įkėlimo variklis turi rekonstruoti. Pataisymas apeina abi problemas, tiesiog neliesdamas to, ko liesti nereikia

Kodėl suspaustų baitų kopijavimas yra įdomiausia dalis?

Zip įrašas, kopijuojamas suspaustu lygmeniu, kainuoja tik srauto kopiją. Tas pats įrašas, praeinantis įprastu rašymo keliu, kainuoja išpakavimą (inflate) įeinant ir suspaudimą (deflate) išeinant, o deflate yra brangesnė pusė. Darbaknygėje su didele suvestinių lentelės talpykla ir keliolika įterptų vaizdų šis skirtumas yra skirtumas tarp pataisymo, kuris baigiasi per laiką, per kurį parašomas naujas lapas, ir pataisymo, kuris didžiąją laiko dalį praleidžia iš naujo suspausdamas baitus, kurių niekada net nepatikrino

Tam HotXLS naudoja CopyCompressedFrom, kuris šaltinio įrašo suspaustus baitus rašo tiesiai į tikslinį archyvą. Kai įrašo tokiu būdu nukopijuoti negalima, nes jis naudoja kitokį suspaudimo metodą arba silpną šifravimą, rašytuvas persijungia į dekompresuoto srauto kopiją, o ne sužlunga. Katalogo žymeklio įrašai praleidžiami, nes rašytuvas sukuria savus

Pakeisti vietoje arba rašyti į naują failą

Du perkrovimai (overload) apima dvi šios užduoties formas. Vietinis variantas rezultatą laikinai parengia laikinajame faile šalia originalo, uždaro šaltinio saugiklį, tada ištrina ir pervadina, todėl gedimas rašymo viduryje palieka originalą nepaliestą. Aiškaus tikslo variantas palieka šaltinį nepaliestą ir gali arba pakeisti lapą, arba pridėti naują:

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

Įterpimo variantas priima šaltinio ir tikslo kelius plius InsertSheet:

  // Šaltinis lieka nepaliestas; tikslas gauna papildomą darbalapį pavadinimu 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;

Įterpimas yra dalis, kuriai reikia tikros apskaitos chirurgijos. Rašytuvas analizuoja lapų registrą xl/workbook.xml faile ir ryšių žemėlapį, kuris kiekvieną lapą sieja su jo dalimi, tada parenka kitą laisvą dalies numerį, lapo identifikatorių ir ryšio identifikatorių. Ryšių tipai seka šaltinio paketo konvencijas, todėl griežto ISO 29500 formato darbaknygės pataisymas generuoja griežtus ryšių tipus, o pereinamojo formato darbaknygės pataisymas generuoja pereinamuosius tipus

Ką pataisymas sąmoningai atmeta ir riboja

Skaičiavimo grandinė atmetama abiem režimais. Pakeitimo režime jos įrašai apibūdina langelius lape, kuris tokia forma jau nebeegzistuoja; įterpimo režime lapo indekso poslinkis ją tiesiog padaro negaliojančia. Excel grandinę perkuria kito perskaičiavimo metu, todėl jos atmetimas yra teisingas, o ne nuostolingas veiksmas. Ši dalis tiesiog neįtraukiama į kopiją, o jos ryšio įrašas ir turinio tipo perrašymas pašalinami chirurgiškai

Dvi kūrimo semantikos pasikeičia pataisymo viduje, ir abi seka tą patį principą: pataisymas neturi trikdyti dalių, kurių jis neperrašė. Eilutės rašomos tiesiai lape, o ne pridedamos į bendrinamų eilučių lentelę, nes šaltinio lentelė perkeliama nepaliesta. O StyleIndex nurodo įrašus šaltinio paketo cellXfs lentelėje, ne stilių lentelę, kurią kuria rašytuvas. Tai reiškia, kad galite nurodyti formatus, kuriuos jau apibrėžia originali darbaknygė, ir tai paprastai yra būtent tai, ko nori duomenų atnaujinimas, bet tai taip pat reiškia, kad turite žinoti, kuris indeksas neša kurį formatą

// Pataisymo viduje StyleIndex indeksuoja ŠALTINIO paketo cellXfs.
// Datai reikia aiškaus indekso, kuris ten susiejamas su datos formatu:
W.WriteDateTime(3, EncodeDate(2026, 8, 22), DateStyleIndexFromTemplate);

// Stiliaus neturintis WriteDateTime perkrovimas pataisymo režime atmetamas,
// nes jis remiasi paties rašytuvo stilių lentele, kurios pataisymas
// niekada nesukuria

Šeši kūrimo įėjimo taškai užrakinti: lentelių, diagramų, vaizdų, komentarų, apibrėžtų vardų ir langelių stilių pridėjimas pataisymo režime sukelia išimtį, o antras apsaugos tinklas uždarymo metu sužlunga, jei bet kuris iš jų skaitiklių yra nenulinis. Kiekvienai iš šių funkcijų reikėtų redaguoti dalis, kurias pataisymas kopijuoja pažodžiui, o iš dalies suredaguotas paketas yra blogiau nei atmesta operacija. Per vieną operaciją galima pataisyti lygiai vieną lapą

Kada pataisyti, o kada įkelti

Pataisymas yra tinkamas įrankis, kai darbaknygė didelė, pakeitimas apsiriboja vienu lapu, o likusi failo dalis turi išlikti nepakitusi iki bito. Tai netinkamas įrankis, kai pakeitimas apima kelis lapus, kai reikia naujo formatavimo ar naujų objektų, arba kai failas pakankamai mažas, kad įprastas įkėlimas ir išsaugojimas nieko nekainuotų. Masiniam generavimui nuo nulio geriau tinka srautinis kelias, aprašytas straipsnyje srautinis tiesioginis rašytuvas, ir jis naudoja tą patį AddRow ir Write* API, todėl perėjimas tarp abiejų yra mechaninis

Lapo lygio manipuliavimas įkeltos darbaknygės viduje, kai iš tikrųjų reikia pilno objektų modelio, aprašytas straipsnyje darbalapių dubliavimas XLSX paketuose. O jei priežastis, dėl kurios svarstote pataisymą, yra ta, kad viso darbaknygės apdorojimas tapo lėtas, prieš pasirenkant metodą verta paskaityti matavimus ir atminties elgseną straipsnyje didelės darbaknygės našumas

Kaip patikrinti, ar pataisymas iš tikrųjų padarė tai, ką manote

Trys patikros pagauna beveik kiekvieną klaidą. Patvirtinkite, kad dalys, kurių tikėjotės išliekant, tebėra archyve, kad xl/calcChain.xml dingęs, ir kad failo atidarymas iš naujo per TXLSXWorkbook praneša tikėtą lapų skaičių – nepakitusį pakeitimo atveju ir padidintą vienetu įterpimo atveju. Pataisyto lapo perskaitymas ir kelių reikšmių bei formulių palyginimas uždaro patikros ciklą

Viena įgyvendinimo detalė iš šios funkcijos kūrimo verta pakartojimo, nes ji gali įkąsti kiekvienam, kas rašo panašų zip lygmens kodą. Darbalapio dalies pavadinimai atitinkami pagal priešdėlį, ir vienetu suklysta priešdėlio ilgio reikšmė reiškia, kad predikatas niekada nesutampa, todėl naujai parašyta dalis susikerta su esamu pavadinimu, o skaitytuvai, kurie ima paskutinį įrašą su tam tikru pavadinimu, tyliai pasirenka neteisingą lapą. Jei pataisymas atrodo sukeitęs dviejų lapų turinį vietomis, pirmiau žiūrėkite į pavadinimų atitikimą, o ne į XML

Pataisymas vietoje, srautinis rašymas ir pilnas darbaknygės objektų modelis pateikiami toje pačioje bibliotekoje Delphi ir C++Builder aplinkoms; funkcijų sąrašas pateikiamas HotXLS Delphi skaičiuoklės komponento puslapyje