Introdução: Por que dominar manipulação de arquivos?
A manipulação de arquivos é uma das habilidades mais práticas e demandadas em programação. Praticamente todo sistema que você construirá precisará ler dados de alguma fonte externa, processá-los e salvar os resultados. Arquivos em formatos como CSV, JSON, XML e Excel são onipresentes no mundo corporativo, em análises de dados, integrações de sistemas e automações.
O diferencial de um programador competente não é conhecer apenas a sintaxe, mas entender quando usar cada formato, suas vantagens e desvantagens, além de como manipulá-los de forma eficiente e robusta. Neste artigo, você aprenderá a trabalhar com esses formatos em Python de maneira prática, direto ao ponto, focando em casos de uso reais.
Trabalhando com CSV: Estrutura simples e universal
CSV (Comma-Separated Values) é um dos formatos mais simples e amplamente adotados. Sua estrutura é basicamente tabular: linhas representam registros e vírgulas separam os campos. A beleza do CSV está na sua universalidade — qualquer editor de texto consegue abrir, e praticamente toda linguagem de programação tem suporte nativo.
Leitura de arquivos CSV
Python fornece o módulo csv na biblioteca padrão, mas para casos mais complexos, a biblioteca pandas é superior. Vou mostrar ambas as abordagens. A primeira é mais leve e útil quando você não quer dependências externas:
import csv
# Leitura simples com csv nativo
with open('vendas.csv', 'r', encoding='utf-8') as arquivo:
leitor = csv.DictReader(arquivo)
for linha in leitor:
print(f"Produto: {linha['produto']}, Valor: {linha['valor']}")
O DictReader é crucial aqui. Ele transforma cada linha em um dicionário usando os cabeçalhos como chaves, tornando o acesso aos dados muito mais intuitivo do que índices numéricos. Sem ele, você teria que usar índices (linha[0], linha[1]) e o código fica ilegível.
Agora, com pandas (mais poderoso e recomendado para análises):
import pandas as pd
# Leitura com pandas
df = pd.read_csv('vendas.csv')
print(df.head()) # Primeiras 5 linhas
print(df.info()) # Informações sobre tipos de dados
print(df['produto'].unique()) # Valores únicos de uma coluna
A vantagem do pandas é poder fazer filtros, agregações e transformações com uma linha de código. Porém, adiciona dependência. Use pandas quando realmente precisar manipular dados; use csv puro quando apenas ler/escrever.
Escrita em CSV
A escrita é tão simples quanto a leitura:
import csv
dados = [
{'produto': 'Notebook', 'valor': 2500.00, 'categoria': 'Eletrônicos'},
{'produto': 'Mouse', 'valor': 50.00, 'categoria': 'Periféricos'},
{'produto': 'Teclado', 'valor': 150.00, 'categoria': 'Periféricos'}
]
with open('produtos.csv', 'w', newline='', encoding='utf-8') as arquivo:
campos = ['produto', 'valor', 'categoria']
escritor = csv.DictWriter(arquivo, fieldnames=campos)
escritor.writeheader() # Escreve a linha de cabeçalho
escritor.writerows(dados) # Escreve todos os dados
Pontos críticos: use newline='' para evitar linhas em branco extras (comportamento padrão do Python em Windows), defina encoding='utf-8' para caracteres especiais funcionarem corretamente, e sempre especifique fieldnames para garantir a ordem das colunas.
JSON: Flexibilidade e integração de APIs
JSON (JavaScript Object Notation) é o padrão atual para troca de dados entre sistemas e APIs. Sua estrutura de chave-valor permite dados aninhados e mais complexos que CSV. Python trata JSON nativamente através do módulo json, transformando strings JSON em dicionários Python e vice-versa.
Leitura e parsing de JSON
import json
# Leitura de arquivo JSON
with open('config.json', 'r', encoding='utf-8') as arquivo:
configuracao = json.load(arquivo)
print(configuracao['banco_dados']['host'])
print(configuracao['banco_dados']['porta'])
# Parsing de string JSON
resposta_api = '{"status": "sucesso", "dados": [1, 2, 3]}'
dados = json.loads(resposta_api)
print(dados['status'])
A distinção importante: json.load() lê direto de um arquivo, enquanto json.loads() (note o 's') parseia uma string. Use a primeira quando trabalhar com arquivos, a segunda ao processar respostas de APIs.
Escrita e geração de JSON
import json
from datetime import datetime
# Dados Python (dicionários e listas)
usuario = {
'id': 1,
'nome': 'João Silva',
'email': 'joao@example.com',
'tags': ['admin', 'desenvolvedor'],
'ativo': True,
'criado_em': datetime.now().isoformat()
}
# Escrita em arquivo
with open('usuario.json', 'w', encoding='utf-8') as arquivo:
json.dump(usuario, arquivo, indent=2, ensure_ascii=False)
# Conversão para string (sem escrever em arquivo)
json_string = json.dumps(usuario, indent=2, ensure_ascii=False)
print(json_string)
Os parâmetros indent=2 formatam o JSON com identação legível (fundamental para debugar), e ensure_ascii=False permite caracteres acentuados. Sem este último, você verá \u00e3 no lugar de ã.
Tratamento de erros e dados complexos
JSON tem limitações: não suporta datas, funções ou tipos customizados nativamente. Para contornar isso:
import json
from datetime import datetime
from decimal import Decimal
class Encoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
if isinstance(obj, Decimal):
return float(obj)
return super().default(obj)
dados = {
'valor': Decimal('19.99'),
'data': datetime(2024, 1, 15)
}
json_string = json.dumps(dados, cls=Encoder, indent=2)
print(json_string)
Criando um encoder customizado, você define como objetos não-serializáveis devem ser tratados. Isso é essencial ao trabalhar com APIs que exigem tipos específicos.
XML: Hierarquia e validação em dados estruturados
XML é mais verboso que JSON e CSV, mas oferece suporte a validação por schema, namespaces e é ainda amplamente usado em integrações corporativas legadas. Python oferece múltiplas bibliotecas; vou focar na xml.etree.ElementTree, que vem na biblioteca padrão.
Leitura de XML
import xml.etree.ElementTree as ET
# Parse de arquivo XML
tree = ET.parse('pedidos.xml')
raiz = tree.getroot()
# Iteração simples
for pedido in raiz.findall('pedido'):
numero = pedido.find('numero').text
cliente = pedido.find('cliente').text
print(f"Pedido {numero}: {cliente}")
# Acesso com namespaces
arquivo_ns = ET.parse('documento_ns.xml')
ns = {'ex': 'http://example.com/schema'}
for item in arquivo_ns.findall('ex:item', ns):
print(item.text)
A hierarquia XML é natural com Element Tree. Use find() para um elemento, findall() para múltiplos, e .text para obter o conteúdo. Namespaces exigem dicionários específicos no findall().
Escrita de XML
import xml.etree.ElementTree as ET
# Criar raiz
raiz = ET.Element('catalogo')
# Adicionar elementos filhos
for i, produto in enumerate([
{'nome': 'Laptop', 'preco': 2000},
{'nome': 'Mouse', 'preco': 45}
], 1):
elem_produto = ET.SubElement(raiz, 'produto')
elem_produto.set('id', str(i))
elem_nome = ET.SubElement(elem_produto, 'nome')
elem_nome.text = produto['nome']
elem_preco = ET.SubElement(elem_produto, 'preco')
elem_preco.text = str(produto['preco'])
# Escrever em arquivo com indentação
tree = ET.ElementTree(raiz)
tree.write('catalogo.xml', encoding='utf-8', xml_declaration=True)
XML gerado fica sem formatação por padrão em ElementTree. Para visualizar com indentação:
def indentar(elem, nivel=0):
indent = "\n" + " " * nivel
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = indent + " "
if not elem.tail or not elem.tail.strip():
elem.tail = indent
for child in elem:
indentar(child, nivel + 1)
if not child.tail or not child.tail.strip():
child.tail = indent
else:
if nivel and (not elem.tail or not elem.tail.strip()):
elem.tail = indent
indentar(raiz)
tree = ET.ElementTree(raiz)
tree.write('catalogo_formatado.xml', encoding='utf-8', xml_declaration=True)
Não é elegante, mas funciona. Bibliotecas como lxml fazem isso automaticamente, mas exigem instalação externa.
Excel com openpyxl: Manipulação profissional de planilhas
Arquivos Excel (.xlsx) são ubíquos em negócios. openpyxl é a biblioteca padrão para ler e escrever Excel em Python, suportando formatação, fórmulas, gráficos e validação.
Instalação e conceitos básicos
pip install openpyxl
Um arquivo Excel é uma coleção de sheets (abas). Cada sheet tem células organizadas em linhas e colunas. Você acessa células por índice numérico (A1, B2) ou por coordenadas (1, 1).
Leitura de Excel
from openpyxl import load_workbook
# Carregar workbook
wb = load_workbook('relatorio.xlsx')
# Acessar sheet ativa ou por nome
ws = wb.active
# ou: ws = wb['Vendas']
# Ler célula individual
valor = ws['A1'].value
valor_alt = ws.cell(row=1, column=1).value
# Iterar sobre linhas
for linha in ws.iter_rows(min_row=2, max_row=10, values_only=True):
print(linha)
# Obter todas as linhas com dados
for linha in ws.iter_rows(values_only=True):
if any(linha): # Ignora linhas vazias
print(linha)
wb.close()
iter_rows(values_only=True) retorna apenas os valores das células. Sem values_only=True, retorna objetos Cell, úteis quando você precisa de formatação ou fórmulas.
Escrita e criação de planilhas
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Alignment
# Criar novo workbook
wb = Workbook()
ws = wb.active
ws.title = "Produtos"
# Escrever dados simples
ws['A1'] = 'Produto'
ws['B1'] = 'Quantidade'
ws['C1'] = 'Preço'
# Dados
produtos = [
('Notebook', 5, 2500.00),
('Mouse', 20, 50.00),
('Teclado', 15, 150.00)
]
for idx, (produto, qtd, preco) in enumerate(produtos, start=2):
ws[f'A{idx}'] = produto
ws[f'B{idx}'] = qtd
ws[f'C{idx}'] = preco
# Aplicar formatação ao cabeçalho
font_negrito = Font(bold=True, color="FFFFFF")
preenchimento_azul = PatternFill(start_color="0070C0", end_color="0070C0", fill_type="solid")
alinhamento_centro = Alignment(horizontal="center", vertical="center")
for celula in ['A1', 'B1', 'C1']:
ws[celula].font = font_negrito
ws[celula].fill = preenchimento_azul
ws[celula].alignment = alinhamento_centro
# Ajustar largura das colunas
ws.column_dimensions['A'].width = 20
ws.column_dimensions['B'].width = 15
ws.column_dimensions['C'].width = 15
# Salvar
wb.save('produtos.xlsx')
Formatação é onde openpyxl brilha. Você consegue definir fontes, cores, bordas, alinhamentos e muito mais programaticamente.
Fórmulas e dados dinâmicos
from openpyxl import load_workbook
wb = load_workbook('vendas.xlsx')
ws = wb.active
# Adicionar fórmulas
ws['D1'] = 'Total'
ws['D2'] = '=B2*C2' # Multiplica quantidade por preço
ws['D3'] = '=B3*C3'
# Fórmulas com referências a ranges
ws['E1'] = 'Subtotal'
ws['E5'] = '=SUM(D2:D4)' # Soma os totais
# Colunas calculadas com Python (melhor para dados estáticos)
for row in range(2, 5):
qtd = ws[f'B{row}'].value
preco = ws[f'C{row}'].value
ws[f'D{row}'].value = qtd * preco
wb.save('vendas_processado.xlsx')
Use fórmulas quando os dados serão atualizados no Excel posteriormente. Use cálculos Python quando os dados são estáticos e você não quer que o usuário altere a fórmula acidentalmente.
Leitura e processamento avançado
from openpyxl import load_workbook
from openpyxl.utils import get_column_letter
wb = load_workbook('dados.xlsx')
ws = wb.active
# Obter dimensões da planilha
max_linha = ws.max_row
max_coluna = ws.max_column
# Construir dicionário a partir de dados com cabeçalho
dados = []
cabecalhos = []
# Ler cabeçalhos
for col in range(1, max_coluna + 1):
cabecalho = ws.cell(row=1, column=col).value
cabecalhos.append(cabecalho)
# Ler dados
for linha in range(2, max_linha + 1):
registro = {}
for col in range(1, max_coluna + 1):
valor = ws.cell(row=linha, column=col).value
registro[cabecalhos[col - 1]] = valor
dados.append(registro)
# Processar dados
for registro in dados:
print(f"{registro['nome']} - {registro['valor']}")
wb.close()
Essa abordagem transforma uma planilha em uma lista de dicionários, similar ao DictReader do CSV, facilitando processamento posterior.
Comparação prática: quando usar cada formato
Cada formato tem seu lugar. CSV é ideal para dados tabulares simples e troca de dados entre sistemas; é leve, universal e fácil de debugar. JSON é perfeito para APIs, configurações e dados hierárquicos; é legível e oferece flexibilidade estrutural. XML ainda é usado em integrações corporativas legadas e onde validação de schema é obrigatória; é verboso mas poderoso.
Excel é a escolha quando você precisa enviar dados para usuários não-técnicos, gráficos, formatação visual ou quando a empresa já trabalha com planilhas. Não force usuários de negócio a aprender Python; envie um Excel bem formatado.
# Exemplo integrado: ler CSV, processar, salvar em JSON e Excel
import csv
import json
from openpyxl import Workbook
# 1. Ler CSV
dados_processados = []
with open('entrada.csv', 'r', encoding='utf-8') as f:
leitor = csv.DictReader(f)
for linha in leitor:
# Processar dados
linha['valor_total'] = float(linha['quantidade']) * float(linha['preco'])
dados_processados.append(linha)
# 2. Salvar em JSON
with open('resultado.json', 'w', encoding='utf-8') as f:
json.dump(dados_processados, f, indent=2, ensure_ascii=False)
# 3. Salvar em Excel
wb = Workbook()
ws = wb.active
ws.append(['Produto', 'Quantidade', 'Preço', 'Total'])
for dado in dados_processados:
ws.append([dado['produto'], dado['quantidade'], dado['preco'], dado['valor_total']])
wb.save('resultado.xlsx')
Tratamento de erros e boas práticas
Trabalhar com arquivos sempre envolve riscos: arquivo não existe, permissões insuficientes, dados malformados. Código robusto trata esses cenários:
import csv
import json
from openpyxl import load_workbook
# Leitura segura de CSV
def ler_csv_seguro(caminho):
try:
with open(caminho, 'r', encoding='utf-8') as f:
return list(csv.DictReader(f))
except FileNotFoundError:
print(f"Erro: arquivo '{caminho}' não encontrado")
return []
except UnicodeDecodeError:
print(f"Erro: problema de codificação. Tentando com latin-1...")
with open(caminho, 'r', encoding='latin-1') as f:
return list(csv.DictReader(f))
except Exception as e:
print(f"Erro inesperado: {e}")
return []
# JSON com validação
def ler_json_seguro(caminho):
try:
with open(caminho, 'r', encoding='utf-8') as f:
return json.load(f)
except FileNotFoundError:
print(f"Erro: arquivo '{caminho}' não encontrado")
return None
except json.JSONDecodeError as e:
print(f"Erro: JSON inválido - {e}")
return None
# Excel com backup
def salvar_excel_seguro(workbook, caminho):
import shutil
from pathlib import Path
# Fazer backup do arquivo anterior se existir
if Path(caminho).exists():
shutil.copy(caminho, f"{caminho}.backup")
try:
workbook.save(caminho)
print(f"Arquivo salvo com sucesso: {caminho}")
except PermissionError:
print(f"Erro: sem permissão para escrever em '{caminho}'")
except Exception as e:
print(f"Erro ao salvar: {e}")
# Usar as funções
dados = ler_csv_seguro('dados.csv')
config = ler_json_seguro('config.json')
Pontos-chave: sempre use context managers (with), trate exceções específicas (não genéricas), registre erros de forma útil para debugging, e considere backup de dados críticos.
Conclusão
Dominar manipulação de arquivos em Python significa entender três competências interdependentes. Primeiro, conhecer as características e limitações de cada formato: CSV para simplicidade, JSON para flexibilidade, XML para validação estruturada, e Excel para comunicação com usuários não-técnicos. Segundo, saber escolher a biblioteca certa para o trabalho — módulos nativos para tarefas simples, pandas e openpyxl quando precisar de funcionalidades avançadas. Terceiro, sempre escrever código defensivo que trata erros e valida dados, porque dados do mundo real são bagunçados.
O caminho para domínio é praticar com dados reais. Pegue um arquivo CSV de um site como Kaggle, processe-o, converta para JSON, crie uma planilha Excel formatada — esse fluxo prático solidifica seu entendimento de forma que nenhuma leitura de documentação consegue.