Ler e Escrever Arquivos CSV em Python com o Módulo csv
Aprenda a ler e escrever arquivos CSV em Python com o módulo csv da biblioteca padrão: reader, DictReader, DictWriter, dialetos, encoding, ponto-e-vírgula e vírgula decimal no padrão brasileiro, arquivos grandes e quando migrar para o pandas. Guia prático em português.
O CSV (Comma-Separated Values) é, disparado, o formato de dados mais usado no dia a dia de quem programa em Python no Brasil. Exportação de extrato bancário, relatório de vendas do ERP, base de CEPs do Correios, planilha de clientes do CRM, arquivo de dados abertos do governo — tudo chega como CSV. A boa notícia é que o Python já traz um módulo dedicado e robusto para ler e escrever esse formato: o csv, da biblioteca padrão. Neste tutorial você vai aprender a usá-lo com exemplos práticos voltados para a realidade brasileira, incluindo os dois problemas que mais atrapalham por aqui — o ponto-e-vírgula como separador e o encoding de arquivos legados.
Se você já automatiza planilhas Excel com Python ou gera relatórios em PDF, dominar o CSV fecha um ciclo essencial de automação de escritório. Para quem está começando, vale revisar o guia de Python para iniciantes e o de manipulação de arquivos; aqui o foco é um formato específico, mas onipresente.
Por que não usar só str.split(",")
A tentação, ao ver a primeira linha de um CSV, é separar os campos com "campo1,campo2".split(","). Isso funciona para o caso mais simples — mas quebra rápido. Considere uma linha de venda:
"Notebook Dell, 16GB",1,"R$ 4.500,00"
O campo do produto contém uma vírgula dentro de aspas. Um split(",") ingênuo devolve quatro pedaços em vez de três, corrompendo a linha. O módulo csv entende as regras do formato — aspas, vírgulas dentro de campos, quebras de linha embutidas — e faz o trabalho corretamente. Use sempre o módulo csv em vez de split.
Lendo CSV: reader e DictReader
O fluxo de leitura é sempre o mesmo: abrir o arquivo, criar o leitor, iterar. Para um arquivo vendas.csv em UTF-8 com vírgula como separador:
import csv
with open("vendas.csv", "r", encoding="utf-8") as arquivo:
leitor = csv.reader(arquivo)
cabecalho = next(leitor) # consome a primeira linha
for linha in leitor: # cada linha é uma lista de strings
print(linha[0], linha[1])
O csv.reader devolve cada registro como uma lista de strings, acessível por índice. Quando o arquivo tem cabeçalho, é mais legível usar o csv.DictReader, que transforma cada linha em um dicionário usando os nomes das colunas como chaves:
with open("vendas.csv", "r", encoding="utf-8") as arquivo:
leitor = csv.DictReader(arquivo)
for registro in leitor:
print(registro["produto"], registro["valor"])
O DictReader é mais robusto a mudanças na ordem das colunas e deixa o código autodocumentado. Para uma referência rápida do conceito, veja a entrada do glossário sobre CSV.
Escrevendo CSV: writer e DictWriter
Para gravar, use csv.writer com listas ou csv.DictWriter com dicionários. Atenção ao detalhe que mais custa tempo no Windows: sempre abra o arquivo para escrita com newline="".
import csv
registros = [
{"produto": "Notebook Dell, 16GB", "qtd": 1, "valor": 4500.00},
{"produto": "Mouse sem fio", "qtd": 3, "valor": 89.90},
{"produto": "Teclado mecânico", "qtd": 2, "valor": 259.00},
]
with open("saida.csv", "w", encoding="utf-8", newline="") as arquivo:
colunas = ["produto", "qtd", "valor"]
escritor = csv.DictWriter(arquivo, fieldnames=colunas)
escritor.writeheader()
escritor.writerows(registros)
O newline="" impede que o Python traduza o caractere de nova linha no Windows — sem ele, o módulo csv adiciona a sua própria quebra e o arquivo fica com linhas em branco duplicadas. Sem newline="", o mesmo arquivo que abre perfeitamente no Linux aparece “pulando” uma linha a cada registro no Excel.
O cenário brasileiro: ponto-e-vírgula e vírgula decimal
Aqui está a pegadinha mais comum para quem trabalha com dados no Brasil. Como usamos a vírgula como separador decimal (R$ 4.500,00), o Excel em português não pode usar a vírgula também como separador de campos. Ele usa, então, o ponto-e-vírgula. Resultado: a maior parte dos CSVs brasileiros não é separada por vírgula, e sim por ;.
Para ler um arquivo gerado pelo Excel brasileiro, informe o delimitador:
with open("vendas_br.csv", "r", encoding="utf-8") as arquivo:
leitor = csv.DictReader(arquivo, delimiter=";")
for registro in leitor:
# atenção: "valor" vem como "4500,00" (string com vírgula decimal)
valor = float(registro["valor"].replace(".", "").replace(",", "."))
print(registro["produto"], valor)
Repare na conversão do valor: como a vírgula é o decimal, é preciso remover o ponto de milhar e trocar a vírgula por ponto antes de chamar float(). Esse passo é a fonte número um de bugs em pipelines de dados brasileiros.
Dialetos: quando o formato se repete
Se você lê e escreve vários arquivos no mesmo padrão, registre um dialeto em vez de repetir delimiter=";" em todo lugar:
csv.register_dialect(
"excel_br",
delimiter=";",
quotechar='"',
quoting=csv.QUOTE_MINIMAL,
)
with open("vendas_br.csv", "r", encoding="utf-8") as arquivo:
leitor = csv.DictReader(arquivo, dialect="excel_br")
for registro in leitor:
...
O módulo já traz dialetos prontos, como excel (vírgula) e excel-tab (tabulação). Veja os disponíveis com csv.list_dialects().
Encoding: UTF-8, latin-1 e cp1252
O segundo problema mais frequente é o UnicodeDecodeError ao ler um arquivo com acentos. Arquivos modernos costumam vir em UTF-8, mas sistemas legados brasileiros — ERPs antigos, exports de mainframe, planilhas salvas no Windows em empresas que não padronizaram o encoding — frequentemente usam latin-1 (ISO-8859-1) ou cp1252 (Windows-1252). Se você não conhece a origem, uma estratégia robusta é tentar UTF-8 e recuar:
def ler_csv(caminho: str) -> list[dict]:
for encoding in ("utf-8", "latin-1", "cp1252"):
try:
with open(caminho, "r", encoding=encoding, newline="") as arquivo:
return list(csv.DictReader(arquivo))
except UnicodeDecodeError:
continue
raise ValueError(f"Não foi possível ler {caminho} com nenhum encoding")
Ao escrever CSVs, padronize em UTF-8 — é o formato mais portável e o que o pandas, o Google Sheets e a maioria das ferramentas modernas esperam.
Arquivos grandes: processe linha por linha
Arquivos de dados públicos brasileiros podem ser enormes — a base do CNPJ, os dados do CAGED ou os microdados do IBGE costumam ter milhões de linhas. A vantagem do módulo csv é que ele é um iterador preguiçoso: lê uma linha por vez, sem carregar tudo na memória.
total = 0.0
contador = 0
with open("caged.csv", "r", encoding="latin-1", newline="") as arquivo:
leitor = csv.DictReader(arquivo, delimiter=";")
for registro in leitor:
salario = float(registro["salario"].replace(",", "."))
total += salario
contador += 1
print(f"Média salarial: R$ {total / contador:,.2f}")
Aqui está a diferença importante: chamar list(leitor) carrega o arquivo inteiro na memória (rápido, mas inviável para arquivos de vários gigabytes). Iterar diretamente com o for mantém o consumo de memória constante. Para análises que envolvem filtragem, agrupamento e estatísticas, vale migrar para o pandas, que lida com tipos, datas e operações vetorizadas de forma muito mais expressiva.
Quando migrar para o pandas
O módulo csv é a ferramenta certa para transformar, filtrar e reescrever arquivos texto, e para pipelines em que você quer controle total e baixo consumo de memória. Quando o trabalho passa a ser analisar os dados — calcular médias, cruzar tabelas, fazer gráficos, tratar datas —, o pandas encurta o caminho:
import pandas as pd
# lê CSV brasileiro (ponto-e-vírgula e vírgula decimal) de uma vez
df = pd.read_csv("vendas_br.csv", sep=";", decimal=",", encoding="utf-8")
print(df["valor"].sum())
Repare como o pandas trata o decimal="," nativamente, sem a conversão manual. Para comparações de performance e quando considerar alternativas modernas, veja também nosso artigo sobre o Polars. E se os dados precisam trafegar entre sistemas com estrutura hierárquica, o JSON costuma ser uma escolha melhor que o CSV.
Boas práticas que evalam horas de debug
- Sempre passe
encoding="utf-8"ao abrir; recorra alatin-1/cp1252só quando a origem for legada. - Use
newline=""ao escrever — no Windows isso evita linhas duplicadas. - Desconfie do delimitador: no Brasil,
;é mais comum que,. - Converta números tratando a vírgula decimal antes de chamar
float(). - Para arquivos grandes, itere — não chame
list()sobre o leitor inteiro. - Valide dados externos: campos ausentes viram
NonenoDictReader, e use o parâmetrorestvalpara definir um valor padrão.
Com o módulo csv dominado, você fecha a base de toda automação de dados em Python: ler a entrada tabular mais universal do mundo corporativo brasileiro, transformá-la e gerar saídas confiáveis — sejam elas outros CSVs, planilhas Excel ou relatórios em PDF e Word.
Equipe Python Brasil
Contribuidor do Python Brasil — Aprenda Python em Português