Arquivos CSV
Esta aula ensina como manipular arquivos CSV em Python usando o módulo csv, cobrindo leitura, escrita, DictReader/DictWriter e cuidados importantes. Inclui exemplos práticos, boas práticas e exercícios com respostas.
O formato CSV (Comma-Separated Values) é um dos mais comuns para armazenar e trocar dados tabulares. Apesar de simples, ele esconde armadilhas como delimitadores variados, aspas e quebras de linha em campos. Nesta aula, você vai dominar o módulo csv da biblioteca padrão do Python, que fornece ferramentas robustas para ler e escrever esses arquivos de forma correta e eficiente.
Vamos explorar desde a leitura e escrita básicas até o uso de DictReader e DictWriter, que trabalham com dicionários, tornando o código mais legível e menos propenso a erros. Também discutiremos cuidados essenciais, como codificação, delimitadores e injeção de fórmulas, para que seus dados permaneçam íntegros.
Módulo csv
O módulo csv implementa classes e funções para ler e gravar dados tabulares no formato CSV. Ele não é apenas um parser, mas sim um conjunto de ferramentas que lida com as variações do formato, como delimitadores diferentes (vírgula, ponto e vírgula, tabulação) e regras de citação. Usar o módulo csv em vez de manipular strings manualmente evita erros comuns, como a quebra de campos que contêm vírgulas ou aspas.
O coração do módulo são as funções reader() e writer(), que retornam objetos de leitura e escrita. Para leitura, você itera sobre as linhas, cada uma sendo uma lista de strings. Para escrita, você passa listas contendo os valores. O módulo também oferece DictReader e DictWriter, que trabalham com dicionários, mapeando cabeçalhos para valores.
import csv
# Exemplo de leitura básica
with open('dados.csv', newline='', encoding='utf-8') as arquivo:
leitor = csv.reader(arquivo)
for linha in leitor:
print(linha) # cada linha é uma lista de strings
O parâmetro newline='' é recomendado para evitar problemas com quebras de linha em arquivos CSV, especialmente no Windows. O parâmetro encoding define a codificação do arquivo; é crucial para garantir que caracteres especiais sejam lidos corretamente.
Leitura e escrita
Vamos aprofundar a leitura e a escrita. Para ler um arquivo CSV, você pode usar csv.reader(), que retorna um objeto iterável. Cada linha é uma lista de strings. Para escrever, csv.writer() oferece o método writerow() para uma linha e writerows() para várias de uma vez.
import csv
# Escrita básica
with open('saida.csv', 'w', newline='', encoding='utf-8') as arquivo:
escritor = csv.writer(arquivo)
escritor.writerow(['Nome', 'Idade', 'Cidade'])
escritor.writerow(['Ana', '28', 'São Paulo'])
escritor.writerow(['Bruno', '34', 'Rio de Janeiro'])
# Leitura básica
with open('saida.csv', newline='', encoding='utf-8') as arquivo:
leitor = csv.reader(arquivo)
for linha in leitor:
print(linha)
O módulo também permite configurar o delimitador, o caractere de citação e outros parâmetros através do parâmetro delimiter e quotechar. Por exemplo, se o arquivo usa ponto e vírgula (comum em países onde a vírgula é separador decimal), você define delimiter=';'.
import csv
# Lendo um arquivo com delimitador ;
with open('dados_br.csv', newline='', encoding='utf-8') as arquivo:
leitor = csv.reader(arquivo, delimiter=';')
for linha in leitor:
print(linha)
Outra configuração importante é lineterminator para escrita, mas é raro precisar alterar. O padrão é o correto para a plataforma.
DictReader/DictWriter
Quando o arquivo CSV tem cabeçalho, DictReader e DictWriter são extremamente úteis. DictReader usa a primeira linha como chaves do dicionário, e cada linha subsequente vira um dicionário. Isso torna o acesso aos dados mais intuitivo, pois você pode referenciar pelo nome da coluna.
import csv
# Lendo com DictReader
with open('pessoas.csv', newline='', encoding='utf-8') as arquivo:
leitor = csv.DictReader(arquivo)
for registro in leitor:
print(registro['Nome'], '-', registro['Cidade'])
Para escrever com DictWriter, você precisa especificar os nomes das colunas na ordem desejada usando o parâmetro fieldnames. Depois, chame writeheader() para escrever a linha de cabeçalho e writerow() para cada dicionário.
import csv
campos = ['Nome', 'Idade', 'Cidade']
with open('novas_pessoas.csv', 'w', newline='', encoding='utf-8') as arquivo:
escritor = csv.DictWriter(arquivo, fieldnames=campos)
escritor.writeheader()
escritor.writerow({'Nome': 'Carla', 'Idade': '25', 'Cidade': 'Belo Horizonte'})
escritor.writerow({'Nome': 'Diego', 'Idade': '30', 'Cidade': 'Curitiba'})
Uma vantagem do DictWriter é que ele permite ignorar chaves extras ou preencher valores ausentes com um valor padrão usando extrasaction e restval. Por exemplo, se um dicionário tem uma chave que não está em fieldnames, o comportamento padrão é gerar um erro; você pode mudar para extrasaction='ignore' para ignorar.
import csv
campos = ['Nome', 'Idade']
with open('pessoas_simples.csv', 'w', newline='', encoding='utf-8') as arquivo:
escritor = csv.DictWriter(arquivo, fieldnames=campos, extrasaction='ignore')
escritor.writeheader()
escritor.writerow({'Nome': 'Eva', 'Idade': '22', 'Cidade': 'Fortaleza'}) # Cidade será ignorada
Cuidados
Ao trabalhar com CSV, alguns cuidados são essenciais para evitar erros e dados corrompidos. Primeiro, sempre abra o arquivo com newline='' para evitar que o Python interprete quebras de linha de forma inconsistente. Segundo, defina a codificação correta, como utf-8, para suportar caracteres acentuados e emojis. Em alguns casos, pode ser necessário usar utf-8-sig para que o Excel reconheça a codificação.
Outro cuidado é com a injeção de fórmulas em CSV (CSV Injection). Se um campo começa com =, +, - ou @, programas de planilha podem interpretá-lo como fórmula, o que pode ser um vetor de ataque. Para evitar, você pode prefixar esses campos com uma aspa simples ou um espaço, ou usar bibliotecas como defusedcsv. No mínimo, valide os dados antes de escrever.
import csv
def sanitizar(valor):
if valor.startswith(('=', '+', '-', '@')):
return "'" + valor
return valor
with open('seguro.csv', 'w', newline='', encoding='utf-8') as arquivo:
escritor = csv.writer(arquivo)
escritor.writerow(['Nome', 'Fórmula'])
escritor.writerow(['João', sanitizar('=1+1')])
Além disso, lembre-se de que os dados lidos de CSV são sempre strings. Se você precisar de números, converta explicitamente com int() ou float(). E cuidado com valores vazios, que podem quebrar a conversão. Sempre trate exceções ou use funções de conversão seguras.
Boas Práticas e Observações Finais
Uma boa prática é usar with para abrir arquivos, garantindo que sejam fechados corretamente. Outra é separar a lógica de leitura/escrita da lógica de negócio. Ao ler grandes arquivos, processe linha por linha em vez de carregar tudo na memória. E, se possível, use DictReader e DictWriter para tornar o código mais claro e menos propenso a erros de índice.
Considere também a biblioteca pandas para análises complexas, mas para tarefas simples, o módulo csv é leve e suficiente. Por fim, teste sempre com arquivos de exemplo que contenham casos extremos, como campos com vírgulas, aspas e quebras de linha.
Referências
- Documentação oficial do módulo csv (Python)
- Tutorial de CSV em Python (Real Python)
- Documentação de I/O do Python
- OWASP: CSV Injection
- Unicode HOWTO do Python
- Documentação do pandas.read_csv
Exercícios
Escreva um programa que leia um arquivo CSV chamado
notas.csvcom colunasalunoenota, e calcule a média das notas. Imprima a média.✓ Resposta:import csv with open('notas.csv', newline='', encoding='utf-8') as arquivo: leitor = csv.DictReader(arquivo) notas = [] for linha in leitor: notas.append(float(linha['nota'])) media = sum(notas) / len(notas) if notas else 0 print(f'Média: {media:.2f}')Crie um script que escreva um arquivo CSV chamado
produtos.csvcom os camposnome,precoequantidadepara três produtos usandoDictWriter.✓ Resposta:import csv campos = ['nome', 'preco', 'quantidade'] produtos = [ {'nome': 'Caneta', 'preco': '1.50', 'quantidade': '100'}, {'nome': 'Caderno', 'preco': '12.90', 'quantidade': '50'}, {'nome': 'Mochila', 'preco': '89.90', 'quantidade': '20'} ] with open('produtos.csv', 'w', newline='', encoding='utf-8') as arquivo: escritor = csv.DictWriter(arquivo, fieldnames=campos) escritor.writeheader() for produto in produtos: escritor.writerow(produto)Leia um arquivo CSV com delimitador ponto e vírgula (
;) e imprima cada linha. O arquivo chama-sedados_br.csv.✓ Resposta:import csv with open('dados_br.csv', newline='', encoding='utf-8') as arquivo: leitor = csv.reader(arquivo, delimiter=';') for linha in leitor: print(linha)Implemente uma função
sanitizar_campoque adiciona uma aspa simples no início se o valor começar com=,+,-ou@. Use-a para escrever um CSV seguro a partir de uma lista de dicionários.✓ Resposta:import csv def sanitizar_campo(valor): if valor.startswith(('=', '+', '-', '@')): return "'" + valor return valor campos = ['nome', 'comando'] dados = [ {'nome': 'Ana', 'comando': '=1+1'}, {'nome': 'Bruno', 'comando': 'normal'} ] with open('seguro.csv', 'w', newline='', encoding='utf-8') as arquivo: escritor = csv.DictWriter(arquivo, fieldnames=campos) escritor.writeheader() for item in dados: item['comando'] = sanitizar_campo(item['comando']) escritor.writerow(item)Dado um arquivo
pessoas.csvcom cabeçalho, useDictReaderpara filtrar as pessoas com idade maior que 30 e imprimir seus nomes.✓ Resposta:import csv with open('pessoas.csv', newline='', encoding='utf-8') as arquivo: leitor = csv.DictReader(arquivo) for registro in leitor: idade = int(registro['idade']) if idade > 30: print(registro['nome'])