Imagine uma tarefa noturna automatizada que constrói um livro de faturas em Pascal e o exporta como CSV para ser importado por um sistema a jusante. Os valores parecem corretos ao abrir no Excel. O ficheiro CSV abre sem problemas num editor de texto. Contudo, o sistema de importação falha na leitura da coluna de totais porque o campo de valor na linha 42 contém a string =SUM(D2:D41) — a fórmula em texto literal — e não o valor numérico calculado. Não há qualquer erro no código: este é o comportamento documentado e constitui o primeiro aspeto a compreender na exportação com o HotXLS. O gerador serializa o modelo da célula exatamente como este se encontra, e uma célula de fórmula cujo valor nunca foi calculado tem apenas o texto da fórmula para exportar
Por que o seu CSV contém fórmulas em vez de números
O HotXLS armazena o texto da fórmula e o seu valor calculado como dois elementos independentes. Por padrão, o método SaveAsCSV não executa a avaliação das fórmulas durante a exportação: o fluxo de exportação não deve alterar o estado do livro de cálculo nem correr o risco de bloqueios em fórmulas circulares ou complexas. Ficheiros gerados e guardados pelo próprio Excel armazenam os valores já calculados junto às fórmulas, pelo que a sua exportação posterior funciona de forma direta. Contudo, o problema manifesta-se em livros criados no seu código, onde as fórmulas foram inseridas mas nunca executadas. A solução consiste em materializar esses valores antes de iniciar a exportação, recorrendo ao método Calculate (o mesmo motor que processa referências entre folhas e funções personalizadas):
var
Book: TXLSXWorkbook;
Sheet: TXLSXWorksheet;
R: Integer;
begin
Book := TXLSXWorkbook.Create;
try
Book.Open('invoice-run.xlsx');
Sheet := Book.Sheets[0];
// Materializar os resultados das fórmulas para que o CSV contenha números e não o texto '=...'
for R := 2 to 41 do
if Sheet.Cells[R, 4].Formula <> '' then
Sheet.Cells[R, 4].Value := Book.Calculate(Sheet.Cells[R, 4].Formula);
Book.SaveAsCSV('feed.csv', 0, ','); // folha 0, vírgula
Book.SaveAsCSV('feed.tsv', 0, #9); // a mesma folha em formato TSV
finally
Book.Free;
end;
end;
Preste atenção ao que o ciclo iterativo realiza: substitui o conteúdo das células de fórmula pelo valor calculado. Este comportamento é o correto para uma exportação temporária, mas seria incorreto se pretendesse gravar novamente o livro como .xlsx no final do processo, pois estaria a substituir as fórmulas por números estáticos. Realize a exportação a partir de uma cópia ou limite a substituição de valores apenas ao fluxo de exportação. O motor que processa o método Calculate disponibiliza suporte avançado, incluindo o registo de funções personalizadas, aspeto detalhado no artigo sobre o motor de fórmulas e funções personalizadas do HotXLS
As garantias do gerador de ficheiros delimitados
A gravação de ficheiros CSV produz codificação UTF-8 com marcador de ordem de bytes (BOM), quebras de linha CRLF e regras de aspas da especificação RFC 4180. Qualquer campo que contenha o delimitador, aspas ou quebras de linha é delimitado por aspas, e as aspas internas são duplicadas. As datas são exportadas no formato yyyy-mm-dd hh:nn:ss, independentemente da formatação configurada na folha. Esta é a opção correta para integração automática de sistemas, embora possa surpreender quem esperasse a exportação do aspeto visual. As células de rich text são convertidas em texto simples concatenando os seus vários segmentos
Estas definições padrão evitam a maioria dos erros de importação, mas duas delas devem ser integradas na especificação do processo: a primeira é o marcador BOM (que permite ao Excel abrir o ficheiro mantendo os caracteres acentuados legíveis, embora alguns analisadores estritos tratem esses três bytes iniciais como dados; se for o caso do seu importador, remova-os no processamento); a segunda é o formato TSV, que partilha o mesmo código de escrita alterando apenas o delimitador para o caractere de tabulação (#9). A folha a exportar é selecionada pelo índice baseado em 0 na sobrecarga de múltiplos argumentos, enquanto a assinatura simples SaveAsCSV(FileName) exporta a folha ativa
A exportação para HTML é uma visualização e não um formato de transferência
Ao contrário do CSV (que descarta toda a informação exceto os valores), o método SaveAsHTML tenta preservar o aspeto visual: gera uma tag <table> por folha, traduz as uniões de células em atributos colspan e rowspan e inclui as regras de formatação como estilos CSS inline. As cores associadas a temas do Excel não são resolvidas, pelo que modelos que dependam destas paletes são exibidos com menor detalhe. Defina cores RGB explícitas em qualquer elemento que deve manter a estética na exportação. O objeto de opções configura o resultado final:
var
Opts: TXLSXHtmlExportOptions;
begin
Opts := TXLSXHtmlExportOptions.Create;
try
Opts.Title := 'Weekly settlement';
Opts.TableClass := 'report-grid'; // classe CSS para associar à folha de estilos da página hospedeira
Opts.WriteDocument := True; // página completa e não apenas um fragmento
if Book.SaveAsHTML('settlement.html', 0, Opts) <> 0 then
raise Exception.Create('Sheet index out of range');
finally
Opts.Free;
end;
end;
Dois detalhes no exemplo merecem atenção: definir WriteDocument como False gera apenas um fragmento de tabela em vez de uma página HTML completa, útil para incorporar uma visualização num layout existente (atribua a classe em TableClass e delegue a estilização na folha de estilos do site); a convenção de retorno inverte a lógica habitual da biblioteca, devolvendo 0 em caso de sucesso e -1 se o índice da folha for inválido (como tal, uma validação baseada em = 1 reportará exportações bem-sucedidas como erros). Se necessitar apenas de exportar uma região e não a folha completa (por exemplo, para enviar por e-mail), o método TXLSXRange.SaveAsHTML exporta qualquer intervalo retangular aplicando as mesmas regras
A saída RTF e os cenários em que se justifica
A quarta opção de exportação escreve tabelas no formato RTF 1.6 (uma folha por chamada ao método SaveAsRTF). As larguras das colunas são estimadas a aproximadamente 96 twips por caractere. A limitação estrutural a ter em conta reside no facto de as células unidas não se expandirem no resultado: apenas a célula âncora exibe o conteúdo, sendo as células cobertas emitidas em branco. Esta particularidade exclui o formato RTF de layouts complexos. Contudo, continua a justificar-se como a via mais direta para integrar dados tabelados em processadores de texto ou em sistemas legados de gestão documental que não suportem HTML
Conversão inversa: a importação de CSV é destrutiva por definição
A leitura de CSV tem regras próprias: o método OpenCSV limpa o livro por completo e reconstrói-o com uma única folha chamada Sheet1. Tem comportamento idêntico ao de um construtor e não a uma união (merge); como tal, nunca o execute num livro que contenha dados não guardados. Passar o caractere #0 como separador ativa a deteção automática do delimitador. O parâmetro ADetectTypes controla a conversão automática de tipos: se ativado, strings numéricas tornam-se números, strings ISO-8601 tornam-se datas e valores textuais true/false passam a booleanos. Desative esta opção se o ficheiro de origem contiver identificadores com zeros à esquerda, códigos postais ou códigos de produtos, os quais seriam corrompidos pela conversão (um zero inicial desaparece quando o texto 00123 é convertido no número 123). Ambas as interfaces expõem a mesma importação. Combinando-a com as funções de exportação descritas, obtém uma ponte de conversão de formatos que dispensa a instalação do Excel no servidor, cenário detalhado no artigo sobre exportação de base de dados para Excel com o HotXLS
Exportar diretamente para um fluxo (stream)
Todas as rotinas de gravação contam com uma sobrecarga para fluxos (streams) a par da gravação em ficheiro: aplica-se a formatos CSV, HTML, RTF e aos próprios livros de cálculo. Em código de servidor, estas sobrecargas constituem a escolha recomendada. Um serviço web que disponibilize a transferência de um CSV pode escrever diretamente num TMemoryStream e entregá-lo à resposta HTTP, evitando criar ficheiros temporários, tarefas de limpeza ou colisões de escrita entre acessos simultâneos. A mesma lógica aplica-se ao envio de exportações para armazenamento de objetos (blob storage) ou em anexos de e-mail. A dependência do sistema de ficheiros deixa de existir
Este padrão de exportação em fluxos paralelos baseia-se na própria arquitetura da biblioteca: ambas as interfaces são motores de leitura e escrita nativos em Object Pascal, eliminando a dependência do Excel, automação COM ou estrangulamentos no processamento concorrente no servidor. Cada pedido web pode gerir o seu próprio objeto de livro, executar os cálculos necessários e transmitir o resultado em fluxos paralelos. A memória RAM é o recurso crítico a monitorizar: o modelo do livro reside na memória durante a exportação, pelo que serviços que processem ficheiros volumosos para conversão em CSV devem limitar as tarefas simultâneas ou criar filas de espera para volumes excessivos, evitando picos de consumo
Um detalhe menor: ative IncludeBOM nas opções HTML se o fragmento for guardado como ficheiro autónomo cuja codificação seja lida por outra ferramenta. Se servir o HTML diretamente via HTTP, declare o charset nos cabeçalhos da resposta
Quando a codificação de caracteres falha
A questão de suporte mais habitual na exportação para CSV é o problema inicial com outra apresentação: o Excel exibe caracteres corrompidos (mojibake) em vez de acentos. A tendência é culpar o gerador, mas este escreve o marcador BOM UTF-8 especificamente para o evitar; o ficheiro está correto ao ser gerado no seu código. O marcador foi corrompido ou removido no percurso: transferências por FTP em modo de texto, cópias de fluxos que ignorem os três bytes iniciais ou proxies que re-codifiquem o tráfego removem o marcador, forçando o Excel a estimar a codificação (o que raramente faz bem). Depure o problema na receção e não na gravação: abra o ficheiro recebido num editor hexadecimal e valide se a sequência EF BB BF se mantém no início do documento
Esta lógica aplica-se aos quatro formatos: a chamada de exportação é a fase simples e o HotXLS adota o comportamento correto em cada decisão. As falhas surgem na integração dos sistemas (onde o texto da fórmula é enviado a um importador que esperava um número, onde o marcador BOM é removido na transferência ou onde células unidas se cruzam com a tabela plana do RTF). Estas particularidades devem constar na especificação do processo de exportação. Para consultar a lista de métodos completa em ambas as interfaces, consulte a página do HotXLS Component