Por que estamos a escrever isto: somos a Geonode e vendemos proxies a pessoas que recolhem dados, pelo que vemos muitos conjuntos de dados extraídos a serem gravados no disco no formato errado. A advertência é simples — a escolha do formato não tem nada a ver com proxies e não ganhamos dinheiro com a vossa decisão neste caso. O que isso afeta é a vossa fatura de armazenamento, o vosso tempo de processamento e a quantidade de tempo que passam durante a semana a depurar o motivo pelo qual um campo que contém uma vírgula interrompeu uma importação a jusante. Esses são custos reais e estão inteiramente sob o vosso controlo antes de gravarem o primeiro registo.
A diferença fundamental: um é uma norma, o outro é um hábito
É isto que é preciso compreender em primeiro lugar, porque tudo o resto decorre daí.
O JSON está normalizado. A RFC 8259 é um documento do «Standards Track» da Internet. Possui uma gramática formal, requisitos obrigatórios e existe explicitamente para eliminar «inconsistências com outras especificações do JSON» e corrigir «erros de especificação». Se dois analisadores JSON não chegarem a um consenso, pelo menos um deles está errado e a especificação indica qual.
O CSV não o é. A RFC 4180 é informativa e afirma-o de forma muito clara:
Embora existam várias especificações e implementações para o formato CSV... não existe nenhuma especificação formal, o que permite uma grande variedade de interpretações dos ficheiros CSV. Esta secção documenta o formato que parece ser seguido pela maioria das implementações.
A expressão «parece ser seguido pela maioria das implementações» tem um peso significativo nessa frase. A RFC 4180 é uma descrição de práticas comuns, não uma definição. Se dois analisadores CSV discordarem, ambos podem estar certos.
É por isso que os problemas com o CSV têm o caráter que têm. Não se trata tanto de erros, mas sim de divergências legítimas sobre um formato que nunca foi totalmente definido — e é também por isso que surgem nas interfaces de integração, meses depois de o ficheiro ter sido criado, nas ferramentas de outra pessoa.
O que o CSV realmente garante
A RFC 4180 documenta as convenções comuns, e vale a pena conhecê-las, pois é nos desvios que residem os problemas.
Os registos são separados por CRLF. O último registo pode ou não ter uma quebra de linha no final. Pode haver uma linha de cabeçalho opcional. Os campos são separados por vírgulas, cada linha deve ter o mesmo número de campos e «os espaços são considerados parte de um campo e não devem ser ignorados».
É na questão das aspas que as coisas ficam interessantes:
Cada campo pode ou não estar entre aspas duplas (no entanto, alguns programas, como o Microsoft Excel, não utilizam aspas duplas de todo).
E os campos «que contenham quebras de linha (CRLF), aspas duplas e vírgulas devem ser colocados entre aspas duplas», sendo que uma aspa dupla embutida é escapada «precedendo-a por outra aspa dupla».
Repare nos verbos modais. «Pode ou não.» «Deve.» O RFC descreve tendências. E a nota entre parênteses sobre o Excel é o documento a admitir, em 2005, que a ferramenta CSV mais utilizada no mundo não segue a convenção.
As consequências práticas, pela ordem em que irão afetá-lo:
Os delimitadores variam consoante a localização. Os países que utilizam uma vírgula como separador decimal utilizam normalmente um ponto e vírgula como delimitador de campos. Um ficheiro exportado por um colega na Alemanha pode não ser analisado por um leitor baseado em vírgulas, e nenhum de vocês fez nada de errado.
A codificação não é declarada. Nada num ficheiro CSV indica a sua codificação de caracteres. UTF-8, Latin-1, Windows-1252 e UTF-16 produzem todos um ficheiro que se parece com CSV, mas que é interpretado como «mojibake» num analisador incorreto. As marcas de ordem de bytes aparecem de forma inconsistente e impedem a análise correta dos cabeçalhos.
Os finais de linha variam. CRLF, LF e — em campos que contêm novas linhas incorporadas — qualquer um deles, dentro de aspas.
Não existem tipos. Tudo é texto. 007 torna-se 7, 2026-09-02 torna-se uma data numa ferramenta e uma cadeia de caracteres noutra, e um + inicial desaparece. A conversão de um ficheiro CSV através de uma folha de cálculo implica, de facto, perdas de informação.
E os ficheiros CSV podem executar código. Um campo que comece por =, +, - ou @ pode ser interpretado como uma fórmula pelo software de folha de cálculo. Trata-se de injeção de fórmulas, uma vulnerabilidade real quando se gravam dados fornecidos pelo utilizador num ficheiro CSV que alguém irá abrir no Excel; a medida de mitigação consiste em prefixar esses campos com uma aspa simples ou neutralizá-los de outra forma antes da gravação. Se o seu pipeline produz ficheiros CSV a partir de conteúdo extraído ou enviado pelo utilizador, vale a pena tratar esta questão de forma deliberada.
O que o JSON garante e onde ainda apresenta falhas
A especificação do JSON é mais rigorosa e, consequentemente, as garantias são mais sólidas.
A codificação está definida. RFC 8259 §8.1: «O texto JSON trocado entre sistemas que não fazem parte de um ecossistema fechado DEVE ser codificado utilizando UTF-8.» Estabelece também que as implementações «NÃO DEVEM adicionar uma marca de ordem de bytes» ao texto JSON transmitido pela rede, embora permitam que os analisadores a ignorem. Toda a classe de problemas relacionados com a adivinhação da codificação que afeta o CSV simplesmente não existe aqui.
Existem tipos. Cadeias de caracteres, números, valores booleanos, nulos, objetos e matrizes são distinguíveis na gramática. "007" e 7 são valores diferentes e permanecem diferentes.
O aninhamento é nativo. Os dados hierárquicos têm uma representação óbvia, em vez de exigirem uma convenção sobre a qual ninguém chegou a acordo.
Dois aspetos em que o JSON é menos absoluto do que as pessoas supõem:
As chaves duplicadas são apenas desaconselhadas. A especificação diz que «Os nomes dentro de um objeto DEVEM ser únicos» — DEVEM, não TÊM DE SER. E é clara quanto à consequência: quando os nomes não são únicos, «o comportamento do software que recebe tal objeto é imprevisível. Muitas implementações reportam apenas o último par nome/valor. Outras implementações reportam um erro ou não conseguem analisar o objeto.»
A precisão numérica é uma orientação, não uma regra. A especificação permite que as implementações definam limites de intervalo e precisão, e observa que uma boa interoperabilidade resulta de não se esperar mais do que o que a norma IEEE 754 binary64 proporciona. Identifica diretamente o caso de falha: «Um número JSON como 1E400 ou 3,141592653589793238462643383279 pode indicar potenciais problemas de interoperabilidade.»
Na prática, trata-se de um bug silencioso que é distribuído. Identificadores grandes de 64 bits perdem precisão quando analisados como números em JavaScript, não ocorre nenhuma exceção e dois registos distintos podem tornar-se o mesmo valor. A medida de mitigação padrão consiste em serializar inteiros grandes como cadeias de caracteres — o que vale a pena fazer no momento em que se escrevem os dados, em vez de se descobrir isso mais tarde. Abordámos a questão do analisador neste contexto no nosso guia sobre JSON.parse.
Tamanho e velocidade
A relação entre tamanho e velocidade é real, e o resultado nem sempre é o que as pessoas esperam.
O CSV é mais pequeno para dados tabulares simples, normalmente por uma margem considerável, porque os nomes dos campos aparecem apenas uma vez no cabeçalho, em vez de aparecerem em cada registo. Um milhão de linhas com cinco campos armazena cinco nomes de campos no CSV e cinco milhões no JSON.
A compressão reduz drasticamente essa diferença. As chaves repetidas comprimem-se extremamente bem. Após a compressão com gzip, a penalização do JSON em registos uniformes reduz-se frequentemente a algo modesto — ocasionalmente a nada. Se estiver a armazenar dados comprimidos, e deveria estar, o argumento do tamanho a favor do CSV é muito mais fraco do que os números brutos sugerem.
O CSV é analisado mais rapidamente em casos simples e mais lentamente nos casos corretos. Um analisador ingênuo do tipo «split(',')» é muito rápido, mas errado. Um analisador em conformidade, que lida corretamente com aspas, novas linhas incorporadas e aspas escapadas, aproxima-se mais do custo da análise do JSON. A maioria das comparações de velocidade do CSV está, na verdade, a comparar discretamente um analisador errado com um correto.
O verdadeiro custo do JSON é a memória, não a CPU. Um único documento JSON de grande dimensão tem, geralmente, de ser mantido na memória para ser analisado. Um CSV pode ser processado linha a linha a partir de um fluxo com consumo de memória constante. Para um ficheiro de dez gigabytes, essa diferença não é um pormenor de desempenho; é a diferença entre o possível e o impossível numa determinada máquina.
E é exatamente esse o problema que a secção seguinte resolve.
O meio-termo: JSON Lines
O JSON Lines — também conhecido como NDJSON ou JSON delimitado por novas linhas — consiste num documento JSON por linha, sem um array de contenção. É o formato que a maioria das pessoas deveria utilizar e que, comparativamente, poucos conhecem.
{"id": 1, "name": "Ada", "tags": ["engineer"]}
{"id": 2, "name": "Grace", "tags": ["engineer", "admiral"]}
O que lhe oferece:
Streaming. Cada linha é analisada de forma independente, pelo que é possível processar um ficheiro de cem gigabytes com memória constante. Isto elimina a maior desvantagem prática do JSON.
Gravações apenas por acréscimo. Os novos registos são acrescentados ao final. Não há matriz envolvente para fechar, o que significa que não é necessário reescrever o ficheiro e não há saída corrompida se um processo falhar a meio da gravação.
Recuperação parcial. Um ficheiro truncado ainda fornece todas as linhas completas. Um array JSON truncado não fornece absolutamente nada — basta faltar um parêntese e todo o documento fica impossível de analisar. Para qualquer coisa escrita por uma tarefa de longa duração, isto por si só já justifica a escolha.
Paralelismo trivial. Divida por linha e processe os fragmentos de forma independente. Sem estado entre linhas.
Semântica JSON completa. Tipos, aninhamento e codificação inequívoca, tudo mantido.
Os custos são razoáveis e reduzidos: ligeiramente maior do que o CSV, não pode ser aberto diretamente numa folha de cálculo e cada registo contém as suas próprias chaves. Para dados extraídos, saídas de registo, fluxos de eventos e qualquer coisa acrescentada de forma incremental, é a predefinição certa — e é o que sugeriríamos a qualquer pessoa que esteja a gravar saídas de recolha no disco.
Para além de ambos: Parquet e afins
Vale a pena saber isto, porque, no caso de cargas de trabalho analíticas, a questão «JSON versus CSV» é, por vezes, completamente irrelevante.
O Parquet é colunar e binário. Armazena cada coluna de forma contígua, o que significa que uma consulta que abranja três colunas de quarenta leituras apenas acede a essas três. Possui um esquema, comprime muito melhor do que o texto orientado por linhas, uma vez que valores semelhantes ficam juntos, e preserva os tipos com exatidão.
Onde se destaca: consultas analíticas em grandes conjuntos de dados, armazenamento a longo prazo de qualquer volume considerável e qualquer pipeline que alimente um data warehouse. As taxas de compressão em relação ao CSV são frequentemente várias vezes superiores, e as diferenças de desempenho nas consultas são ainda maiores.
Onde fica a perder: não é legível por humanos, não permite acréscimos da mesma forma que o JSON Lines e requer uma biblioteca em vez de um editor de texto. Para streaming, para intercâmbio com pessoas e para pequenos conjuntos de dados, os formatos de texto continuam a ser a escolha correta.
Uma arquitetura comum e sensata: recolher em JSON Lines, porque é fácil de acrescentar dados e tolerante a perdas, e depois converter para Parquet em lotes para análise e arquivo. Cada formato é utilizado onde as suas propriedades são mais úteis.
Escolha por tipo de tarefa
| Tarefa | Formato | Porquê |
|---|---|---|
| Resposta da API Web | JSON | Nativo das ferramentas, tipos e aninhamento do HTTP |
| Dados extraídos gravados de forma incremental | JSON Lines | Permite acréscimos, é transmissível em fluxo e resiste ao truncamento |
| Envio de dados a um colega sem conhecimentos técnicos | CSV | Abre no Excel, o que é o requisito efetivo |
| Configuração | Nenhum dos dois — YAML ou TOML | Os comentários são importantes |
| Conjunto de dados analítico de grande dimensão | Parquet | Leituras colunares, compressão, esquema |
| Importação em massa para bases de dados | CSV | Carregadores nativos de caminho rápido na maioria das bases de dados |
| Fluxos de eventos ou registos | JSON Lines | Um evento por linha, apenas com adição |
| Registos aninhados ou de forma variável | JSON ou JSON Lines | O CSV não consegue expressá-los sem inventar convenções |
| Dados com qualquer texto fornecido pelo utilizador | JSON ou JSON Lines | Evita riscos relacionados com aspas, delimitadores e injeção de fórmulas |
Três regras que resolvem a maioria dos casos sem necessidade de recorrer à tabela.
Se os dados forem planos, uniformes e destinados a uma folha de cálculo ou a um carregador em massa, utilize CSV. Estes são, de facto, os pontos fortes do CSV e nenhum outro formato os oferece de forma tão conveniente. A importação em massa para bases de dados, em particular, é uma vantagem real — a maioria dos motores tem um caminho rápido para o CSV, mas não para o JSON.
Se os dados forem aninhados, de forma variável ou contiverem qualquer coisa digitada pelo utilizador, utilize JSON ou JSON Lines. Aplanar dados aninhados em CSV requer a criação de uma convenção, e todas as convenções criadas para este fim têm sido fonte de erros. Por outro lado, o texto do utilizador contém vírgulas, aspas e novas linhas, que são exatamente o que o CSV lida de forma menos fiável.
Se estiver a escrever registos continuamente, utilize JSON Lines. Não utilize CSV, porque o CSV não tem tipos e irá perdê-los. Não utilize um array JSON, porque não é possível acrescentar-lhe dados com segurança e, caso o processo falhe, fica um ficheiro impossível de analisar.
Perguntas frequentes
O JSON é melhor do que o CSV?
Dependendo da tarefa, sim e não. O JSON é um padrão formal com tipos, aninhamento e codificação UTF-8 obrigatória. O CSV ocupa menos espaço para dados tabulares simples, é facilmente processável e abre em folhas de cálculo. O argumento mais forte é que o CSV não tem uma especificação formal — o RFC 4180 afirma-o explicitamente —, o que o torna menos previsível entre diferentes ferramentas.
Por que é que o meu ficheiro CSV não funciona no Excel?
Normalmente, devido à codificação ou ao delimitador. Os ficheiros CSV não declaram a sua codificação de caracteres, pelo que o Excel tem de adivinhar, e as configurações regionais que utilizam uma vírgula como separador decimal esperam um delimitador de ponto-e-vírgula. Ambos os problemas são inerentes a um formato que nunca especificou nenhum dos dois. Exportar em UTF-8 com um BOM ajuda frequentemente no caso específico do Excel, mas pode confundir outros analisadores.
O que é o JSON Lines e quando devo utilizá-lo?
Um documento JSON por linha, sem matriz de envolventes. Utilize-o sempre que escrever registos de forma incremental — dados extraídos, registos de sistema, fluxos de eventos. Funciona em memória constante, acrescenta dados com segurança, resiste ao truncamento mantendo cada linha completa intacta e preserva os tipos JSON completos e o aninhamento.
O CSV é mais pequeno do que o JSON?
Sem compressão e para dados planos e uniformes, normalmente por uma margem considerável, porque os nomes dos campos aparecem uma única vez em vez de em cada registo. Após a compressão, a diferença diminui drasticamente, uma vez que as chaves repetidas se comprimem muito bem. Se estiver a armazenar dados comprimidos, o argumento do tamanho a favor do CSV é muito mais fraco do que os números brutos sugerem.
O CSV consegue lidar com dados aninhados?
Não de forma nativa. Qualquer aninhamento requer uma convenção criada por si — achatamento com nomes de colunas pontilhados, cadeias JSON dentro das células ou vários ficheiros relacionados. Todas estas opções funcionam, mas significam que o seu CSV deixa de ser legível por ferramentas genéricas sem a sua convenção específica, o que constitui a principal razão para utilizar CSV em primeiro lugar.
O que é mais rápido de analisar, JSON ou CSV?
O CSV, em casos simples, mas a comparação é muitas vezes injusta — um analisador rápido do tipo «split(',')» não é um analisador de CSV correto, e um que lide adequadamente com aspas e novas linhas incorporadas fica muito mais próximo do JSON em termos de custo. A diferença mais importante é a memória: o CSV é processado linha a linha, enquanto um documento JSON geralmente precisa de ser carregado na íntegra, o que o JSON Lines corrige.
São permitidas chaves duplicadas no JSON?
A especificação diz que os nomes «DEVEM ser únicos» em vez de «TÊM de ser», pelo que são tecnicamente permitidos. Também alerta que o comportamento é imprevisível quando não o são — alguns analisadores mantêm o último, outros apresentam erros e outros falham completamente. Trate as duplicatas como um erro no que quer que tenha produzido o documento.
Que formato devo usar para dados extraídos?
JSON Lines, na maioria dos casos. Os registos extraídos estão frequentemente aninhados e têm formas variáveis, algo que o CSV lida mal, e a recolha é incremental, algo que as matrizes JSON lidam mal. Se os dados forem genuinamente planos e se destinarem a uma folha de cálculo ou a um carregamento em massa, o CSV serve — e se criar um ficheiro CSV a partir de texto extraído, neutralize os campos que comecem por =, +, - ou @ para evitar a injeção de fórmulas.
Conclusão
O enquadramento que facilita esta decisão não é «estruturado versus simples». É o facto de um destes formatos ter uma especificação e o outro ter uma descrição das práticas comuns. A RFC 8259 indica o que o JSON deve fazer; a RFC 4180 indica o que os ficheiros CSV parecem fazer habitualmente e expressa isso nas suas próprias palavras.
Essa diferença está na origem de praticamente todos os problemas do CSV — codificações não declaradas, delimitadores dependentes da localização, aspas inconsistentes, tipos perdidos silenciosamente numa folha de cálculo e campos que se transformam em fórmulas. Nenhum destes é um erro no analisador de ninguém. São o resultado previsível de um formato que nunca foi totalmente definido.
Para a maioria das pessoas que escrevem dados em vez de os lerem, o JSON Lines é a resposta e está subutilizado. Mantém os tipos, o aninhamento e a codificação estabelecida do JSON, ao mesmo tempo que elimina a sua única fraqueza real — transmite em fluxo contínuo, acrescenta com segurança e sobrevive a uma gravação truncada com todos os registos completos intactos. Reserve o CSV para as duas tarefas em que realmente se destaca: entregar uma tabela plana a alguém que a irá abrir numa folha de cálculo e carregar em massa uma base de dados. E se o conjunto de dados for grande e analítico, nenhum dos formatos de texto é o destino final adequado; converta-o para um formato colunar e deixe que cada formato cumpra a função para a qual foi concebido.
