O HotXLS consegue reescrever uma única planilha dentro de um pacote XLSX existente sem analisar nem recomprimir o restante do arquivo. TXLSDirectWriter.BeginPatch abre um pacote de origem, copia cada entrada, exceto a planilha alvo, com seus bytes comprimidos exatamente como estavam, e permite que você reescreva aquela única planilha por meio das chamadas comuns AddSheet, AddRow e Write*. Gráficos, caches de tabela dinâmica, temas, estilos e strings compartilhadas nunca chegam a ser descomprimidos
O fluxo de trabalho que isso resolve aparece em relatórios e atualizações de dados. Uma pasta de trabalho chega de uma equipe de negócios carregando tabelas dinâmicas, segmentações de dados, formatos condicionais e uma década de formatação acumulada. Toda noite, uma planilha de dados precisa ser substituída por números atualizados. Carregar e regravar a pasta de trabalho inteira custa minutos por arquivo e, mais importante, arrisca a fidelidade de recursos que o mecanismo de carregamento precisa reconstruir. A aplicação de patch contorna os dois problemas ao não tocar no que não precisa tocar
Por que copiar bytes comprimidos é a parte interessante?
Uma entrada zip copiada no nível comprimido custa uma simples cópia de stream. A mesma entrada, passando por um caminho de gravação normal, custa uma inflação (inflate) na entrada e uma deflação (deflate) na saída, e a deflação é a metade cara. Em uma pasta de trabalho com um grande cache de tabela dinâmica e algumas dezenas de imagens incorporadas, essa diferença é a diferença entre um patch que termina no tempo que leva para escrever a nova planilha e um que passa a maior parte do tempo recomprimindo bytes que nunca sequer examinou
O HotXLS usa CopyCompressedFrom para isso, que grava os bytes comprimidos da entrada de origem diretamente no arquivo de destino. Quando uma entrada não pode ser copiada dessa forma, porque usa um método de compressão diferente ou criptografia fraca, o gravador recorre a uma cópia de stream descomprimida em vez de falhar. Entradas de marcador de diretório são ignoradas, já que o gravador produz as suas próprias
Substituir no local, ou gravar em um novo arquivo
Duas sobrecargas cobrem as duas formas que essa tarefa assume. A forma no local prepara o resultado em um arquivo temporário ao lado do original, fecha o handle de origem, depois exclui e renomeia, de modo que uma falha no meio da gravação deixa o original intacto. A forma com destino explícito deixa a origem intocada e pode substituir uma planilha ou anexar uma nova:
var
W: TXLSDirectWriter;
begin
W := TXLSDirectWriter.Create;
try
W.BeginPatch('monthly-dashboard.xlsx', 'Data'); // no local
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 variante de inserção recebe um caminho de origem e um de destino, além de InsertSheet:
// A origem permanece intocada; o destino ganha uma planilha extra chamada 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;
A inserção é a parte que exige uma cirurgia de contabilidade de verdade. O gravador analisa o registro de planilhas em xl/workbook.xml e o mapa de relacionamentos que vincula cada planilha à sua parte, e então escolhe o próximo número de parte livre, o identificador de planilha e o identificador de relacionamento. Os tipos de relacionamento seguem as convenções do pacote de origem, então aplicar um patch em uma pasta de trabalho ISO 29500 strict emite tipos de relacionamento strict, e aplicar um patch em uma transitória emite tipos transitórios
O que o patch deliberadamente descarta e restringe
A cadeia de cálculo é descartada nos dois modos. No modo de substituição, suas entradas descrevem células de uma planilha que não existe mais naquela forma; no modo de inserção, o deslocamento do índice de planilhas a invalida por completo. O Excel reconstrói a cadeia no próximo recálculo, então descartá-la é o comportamento correto, não uma perda. A parte é deixada de fora da cópia, e sua entrada de relacionamento e sua substituição de tipo de conteúdo são removidas cirurgicamente
Duas semânticas de criação mudam dentro de um patch, e ambas decorrem do mesmo princípio: o patch não deve perturbar partes que não reescreveu. As strings são gravadas embutidas na planilha em vez de adicionadas à tabela de strings compartilhadas, porque a tabela de origem é transferida intocada. E StyleIndex se refere a entradas no cellXfs do pacote de origem, não a uma tabela de estilos que o gravador constrói. Isso significa que você pode referenciar formatos que a pasta de trabalho original já define, o que costuma ser exatamente o que uma atualização de dados quer, mas também significa que você precisa saber qual índice carrega qual formato
// Dentro de um patch, StyleIndex indexa o cellXfs do pacote DE ORIGEM.
// Uma data precisa de um índice explícito que corresponda lá a um formato de data:
W.WriteDateTime(3, EncodeDate(2026, 8, 22), DateStyleIndexFromTemplate);
// A sobrecarga de WriteDateTime sem estilo é rejeitada no modo patch,
// porque ela pressupõe a tabela de estilos própria do gravador, que um
// patch nunca cria
Seis pontos de entrada de criação são bloqueados: adicionar tabelas, gráficos, imagens, comentários, nomes definidos e estilos de célula, todos lançam uma exceção no modo patch, com uma segunda rede de segurança no momento do fechamento, que falha se algum de seus contadores for diferente de zero. Cada um desses recursos exigiria editar partes que o patch copia literalmente, e um pacote parcialmente editado é pior do que uma operação recusada. Exatamente uma planilha pode receber patch por operação
Quando aplicar patch e quando carregar
Aplicar patch é a ferramenta certa quando a pasta de trabalho é grande, a mudança está confinada a uma planilha, e o restante do arquivo precisa sobreviver bit a bit. É a ferramenta errada quando a mudança abrange várias planilhas, quando são necessários formatação ou objetos novos, ou quando o arquivo é pequeno o suficiente para que um carregamento e salvamento normal não custe nada. Para geração em massa a partir do zero, o caminho de streaming descrito em o gravador direto em streaming continua sendo a opção mais adequada, e ele compartilha a mesma API AddRow e Write*, então mover-se entre os dois é mecânico
A manipulação em nível de planilha dentro de uma pasta de trabalho carregada, quando você realmente quer o modelo de objeto completo, é abordada em duplicação de planilhas em pacotes XLSX. E se o motivo pelo qual você está considerando um patch é que o processamento da pasta de trabalho inteira ficou lento, as medições e o comportamento de memória em desempenho de pastas de trabalho grandes vale a pena ler antes de escolher uma abordagem
Verificando se um patch realmente fez o que você pensa
Três verificações capturam quase todos os erros. Confirme que as partes que você esperava que sobrevivessem ainda estão no arquivo, que xl/calcChain.xml desapareceu, e que reabrir o arquivo pelo TXLSXWorkbook relata a contagem de planilhas esperada, inalterada em uma substituição e incrementada em um na inserção. Reler a planilha corrigida e comparar alguns valores e fórmulas fecha o ciclo
Um detalhe de implementação do desenvolvimento desse recurso merece ser repetido, porque pode pegar qualquer pessoa que escreva código semelhante no nível do zip. Os nomes das partes de planilha são comparados por prefixo, e um erro de um dígito no comprimento do prefixo faz com que o predicado nunca combine, então uma parte recém-gravada colide com um nome existente, e leitores que pegam a última entrada com um determinado nome acabam escolhendo silenciosamente a planilha errada. Se um patch parecer ter trocado o conteúdo de duas planilhas, olhe para a correspondência de nomes antes de olhar para o XML
Aplicação de patch no local, gravações em streaming e o modelo de objeto completo da pasta de trabalho fazem parte da mesma biblioteca para Delphi e C++Builder; a lista de recursos está na página do componente de planilhas para Delphi HotXLS