HotXLS може да презапише един работен лист вътре в съществуващ XLSX пакет, без да анализира или прекомпресира останалата част от файла. TXLSDirectWriter.BeginPatch отваря изходен пакет, копира всеки запис освен целевия лист с неговите компресирани байтове дословно, и ви позволява да пресъздадете точно този лист чрез обичайните извиквания AddSheet, AddRow и Write*. Диаграми, pivot кешове, теми, стилове и споделени низове изобщо не се декомпресират
Работният процес, който това решава, се появява при отчитане и опресняване на данни. Работна книга пристига от бизнес екип, носеща pivot таблици, слайсъри, условно форматиране и десетилетие натрупано форматиране. Всяка нощ един лист с данни трябва да бъде заменен с нови числа. Зареждането и повторното записване на цялата работна книга струва минути за файл, и по-важно, рискува вярност по функции, които зареждащият механизъм трябва да пресъздаде. Закърпването заобикаля и двата проблема, като не докосва това, което не му е нужно да докосне
Защо копирането на компресирани байтове е интересната част?
Zip запис, копиран на компресирано ниво, струва копиране на поток. Същият запис, преминал през нормален път на записване, струва разопаковане (inflate) на входа и компресиране (deflate) на изхода, а deflate е скъпата половина. При работна книга с голям pivot кеш и няколко дузини вградени изображения тази разлика е разликата между закърпване, което завършва за времето, необходимо за записване на новия лист, и такова, което прекарва по-голямата част от времето си в прекомпресиране на байтове, които никога не е разглеждало
HotXLS използва CopyCompressedFrom за това, което записва компресираните байтове на изходния запис директно в целевия архив. Когато запис не може да бъде копиран по този начин, защото използва различен метод на компресиране или слабо криптиране, писачът се връща към копиране на декомпресиран поток, вместо да се провали. Записи-маркери за директории се пропускат, тъй като писачът произвежда своите собствени
Замяна на място или записване в нов файл
Две претоварвания (overload) покриват двете форми, които тази задача приема. Формата на място подготвя резултата във временен файл до оригинала, затваря манипулатора на източника, след което изтрива и преименува, така че срив по средата на записването оставя оригинала незасегнат. Формата с изричен целеви файл оставя източника недокоснат и може или да замени лист, или да добави нов:
var
W: TXLSDirectWriter;
begin
W := TXLSDirectWriter.Create;
try
W.BeginPatch('monthly-dashboard.xlsx', 'Data'); // на място
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;
Вариантът за вмъкване приема изходен и целеви път плюс InsertSheet:
// Източникът остава недокоснат; целта получава допълнителен работен лист с име 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;
Вмъкването е частта, която изисква истинска хирургия по счетоводството. Писачът анализира регистъра на листове в xl/workbook.xml и картата на връзки, обвързваща всеки лист с неговата част, след което избира следващия свободен номер на част, идентификатор на лист и идентификатор на връзка. Типовете връзки следват конвенциите на изходния пакет, така че закърпването на строга ISO 29500 работна книга извежда строги типове връзки, а закърпването на преходна извежда преходни типове
Какво закърпването съзнателно изхвърля и ограничава
Веригата за изчисление се изхвърля и в двата режима. В режим на замяна нейните записи описват клетки в лист, който вече не съществува в тази форма; в режим на вмъкване изместването на индекса на листа я прави невалидна изцяло. Excel преизгражда веригата при следващото преизчисление, така че изхвърлянето ѝ е правилно, а не загубващо. Частта се пропуска от копието, а нейният запис за връзка и заместване на тип съдържание се премахват хирургически
Две семантики за създаване се променят вътре в закърпване, и двете следват от един и същ принцип: закърпването не трябва да смущава части, които не е презаписало. Низовете се записват вградени в листа, вместо да се добавят в таблицата на споделени низове, защото изходната таблица преминава недокосната. А StyleIndex сочи към записи в cellXfs на изходния пакет, не към таблица със стилове, изградена от писача. Това означава, че можете да препращате към формати, които оригиналната работна книга вече дефинира, което обикновено е точно това, което иска опресняване на данни, но също означава, че трябва да знаете кой индекс носи какъв формат
// Вътре в закърпване StyleIndex индексира cellXfs на ИЗХОДНИЯ пакет.
// Дата се нуждае от изричен индекс, който сочи там към формат за дата:
W.WriteDateTime(3, EncodeDate(2026, 8, 22), DateStyleIndexFromTemplate);
// Претоварването на WriteDateTime без стил се отхвърля в режим на закърпване,
// защото приема собствената таблица със стилове на писача, каквато закърпване
// никога не създава
Шест входни точки за създаване са блокирани: добавянето на таблици, диаграми, изображения, коментари, дефинирани имена и клетъчни стилове всички повдигат изключение в режим на закърпване, с втора предпазна мрежа при затваряне, която се проваля, ако някой от техните броячи е различен от нула. Всяка от тези функции би изисквала редактиране на части, които закърпването копира дословно, а наполовина редактиран пакет е по-лош от отказана операция. Точно един лист може да бъде закърпен за операция
Кога да закърпвате и кога да зареждате
Закърпването е правилният инструмент, когато работната книга е голяма, промяната е ограничена до един лист, а останалата част от файла трябва да оцелее бит по бит. Той е грешният инструмент, когато промяната обхваща няколко листа, когато е нужно ново форматиране или нови обекти, или когато файлът е достатъчно малък, за да не струва нищо обичайно зареждане и записване. За масово генериране от нулата стрийминг пътят, описан в стрийминг директния писач, остава по-подходящият избор, и той споделя същото API AddRow и Write*, така че преминаването между двата е механично
Манипулирането на ниво лист вътре в заредена работна книга, когато наистина искате пълния обектен модел, е разгледано в дублиране на работни листове в XLSX пакети. И ако причината, поради която обмисляте закърпване, е, че обработката на цялата работна книга е станала бавна, измерванията и поведението на паметта в производителност при големи работни книги си струва да бъдат прочетени, преди да изберете подход
Проверка дали закърпването наистина е направило това, което смятате
Три проверки улавят почти всяка грешка. Потвърдете, че частите, които сте очаквали да оцелеят, все още са в архива, че xl/calcChain.xml го няма, и че повторното отваряне на файла чрез TXLSXWorkbook отчита очаквания брой листове — непроменен за замяна и увеличен с един за вмъкване. Прочитането на закърпения лист обратно и сравняването на няколко стойности и формули затваря цикъла
Една подробност от разработката на тази функция заслужава повтаряне, защото може да ухапе всеки, който пише подобен код на ниво zip. Имената на части за работни листове се съпоставят по префикс, и грешка с едно число в дължината на префикса означава, че предикатът никога не съвпада, така че новозаписана част се сблъсква с вече съществуващо име, и четци, които вземат последния запис с дадено име, тихо избират грешния лист. Ако закърпване изглежда разменя съдържанието на два листа, погледнете съпоставянето на имена, преди да погледнете XML
Закърпването на място, стрийминг записите и пълният обектен модел на работна книга се доставят в една и съща библиотека за Delphi и C++Builder; списъкът с функции е на страницата на HotXLS Delphi компонента за електронни таблици