Programas raramente existem de forma isolada — eles leem configurações, processam dados de entrada, geram relatórios e persistem informações. Arquivos são o mecanismo mais fundamental de persistência em qualquer sistema. Python oferece uma API limpa e expressiva para trabalhar com arquivos de texto, binários e formatos estruturados como CSV e JSON.
Abrindo e Fechando Arquivos
A função open() abre um arquivo e retorna um objeto de arquivo:
# Forma manual — exige fechar explicitamente
arquivo = open("dados.txt", "r", encoding="utf-8")
conteudo = arquivo.read()
arquivo.close()
# Forma recomendada — with fecha automaticamente
with open("dados.txt", "r", encoding="utf-8") as arquivo:
conteudo = arquivo.read()
Sempre especifique encoding="utf-8" — evita problemas com acentuação em diferentes sistemas operacionais.
Modos de Abertura
# Leitura (padrão) — erro se arquivo não existir
with open("arquivo.txt", "r") as f: ...
# Escrita — cria o arquivo ou sobrescreve se existir
with open("arquivo.txt", "w") as f: ...
# Adição — cria ou adiciona ao final
with open("arquivo.txt", "a") as f: ...
# Leitura e escrita
with open("arquivo.txt", "r+") as f: ...
# Modo binário — para imagens, PDFs, etc.
with open("imagem.png", "rb") as f: ...
with open("saida.png", "wb") as f: ...
# Criação exclusiva — erro se arquivo já existir
with open("novo.txt", "x") as f: ...
Lendo Arquivos
# read() — lê o arquivo inteiro como string
with open("texto.txt", "r", encoding="utf-8") as f:
conteudo = f.read()
print(conteudo)
# readline() — lê uma linha por vez
with open("texto.txt", "r", encoding="utf-8") as f:
primeira = f.readline()
segunda = f.readline()
# readlines() — retorna lista de linhas
with open("texto.txt", "r", encoding="utf-8") as f:
linhas = f.readlines()
print(linhas) # ['linha1\n', 'linha2\n', 'linha3\n']
# Iteração direta — mais eficiente para arquivos grandes
with open("texto.txt", "r", encoding="utf-8") as f:
for linha in f:
print(linha.strip()) # strip() remove o \n do final
Para arquivos grandes, a iteração direta é preferível — não carrega tudo na memória de uma vez.
Escrevendo Arquivos
# Escrita simples
with open("saida.txt", "w", encoding="utf-8") as f:
f.write("Primeira linha\n")
f.write("Segunda linha\n")
# writelines() — escreve lista de strings
linhas = ["Ana\n", "Bruno\n", "Carla\n"]
with open("nomes.txt", "w", encoding="utf-8") as f:
f.writelines(linhas)
# print() com file= — prático para formatação
with open("relatorio.txt", "w", encoding="utf-8") as f:
print("=== Relatório ===", file=f)
print(f"Total: {42}", file=f)
# Adicionando ao final
with open("log.txt", "a", encoding="utf-8") as f:
from datetime import datetime
f.write(f"{datetime.now()} — Evento registrado\n")
Trabalhando com Caminhos: pathlib
O módulo pathlib oferece uma forma orientada a objetos e multiplataforma de trabalhar com caminhos — substitui o antigo os.path:
from pathlib import Path
# Criando caminhos
base = Path("/home/usuario/projetos")
arquivo = base / "dados" / "resultado.txt"
print(arquivo) # /home/usuario/projetos/dados/resultado.txt
print(arquivo.name) # resultado.txt
print(arquivo.stem) # resultado
print(arquivo.suffix) # .txt
print(arquivo.parent) # /home/usuario/projetos/dados
# Verificações
print(arquivo.exists())
print(arquivo.is_file())
print(arquivo.is_dir())
# Leitura e escrita diretas
arquivo.parent.mkdir(parents=True, exist_ok=True)
arquivo.write_text("Conteúdo do arquivo", encoding="utf-8")
conteudo = arquivo.read_text(encoding="utf-8")
# Listando arquivos
pasta = Path(".")
for item in pasta.iterdir():
print(item)
# Filtrando por extensão
for py_file in pasta.glob("**/*.py"):
print(py_file)
# Caminho do usuário
home = Path.home()
config = home / ".config" / "meu_app" / "config.json"
Arquivos CSV
CSV (Comma-Separated Values) é o formato mais comum para dados tabulares:
import csv
from pathlib import Path
# Escrevendo CSV
alunos = [
{"nome": "Ana", "nota": 9.5, "turma": "A"},
{"nome": "Bruno", "nota": 7.0, "turma": "B"},
{"nome": "Carla", "nota": 8.5, "turma": "A"},
]
with open("alunos.csv", "w", newline="", encoding="utf-8") as f:
campos = ["nome", "nota", "turma"]
writer = csv.DictWriter(f, fieldnames=campos)
writer.writeheader()
writer.writerows(alunos)
# Lendo CSV
with open("alunos.csv", "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for linha in reader:
print(f"{linha['nome']:10} — nota: {linha['nota']}")
# CSV com delimitador diferente
with open("dados.csv", "r", encoding="utf-8") as f:
reader = csv.reader(f, delimiter=";")
for linha in reader:
print(linha)
Arquivos JSON
JSON é o formato padrão para troca de dados em APIs e configurações:
import json
from pathlib import Path
# Serialização — Python → JSON
config = {
"host": "localhost",
"porta": 5432,
"debug": True,
"tags": ["producao", "v2"],
"timeout": None
}
# Para string
json_str = json.dumps(config, indent=2, ensure_ascii=False)
print(json_str)
# Para arquivo
with open("config.json", "w", encoding="utf-8") as f:
json.dump(config, f, indent=2, ensure_ascii=False)
# Desserialização — JSON → Python
with open("config.json", "r", encoding="utf-8") as f:
dados = json.load(f)
print(dados["host"]) # localhost
print(type(dados)) # <class 'dict'>
# Usando pathlib diretamente
config_path = Path("config.json")
dados = json.loads(config_path.read_text(encoding="utf-8"))
Correspondência de tipos:
JSON Python
─────────────────────
object → dict
array → list
string → str
number → int / float
true/false→ True / False
null → None
Arquivos Binários e pickle
Para serializar objetos Python arbitrários:
import pickle
from dataclasses import dataclass
from typing import List
@dataclass
class ModeloML:
nome: str
parametros: dict
acuracia: float
versao: str
modelo = ModeloML(
nome="ClassificadorSpam",
parametros={"learning_rate": 0.01, "epochs": 100},
acuracia=0.94,
versao="1.0.0"
)
# Salvando
with open("modelo.pkl", "wb") as f:
pickle.dump(modelo, f)
# Carregando
with open("modelo.pkl", "rb") as f:
modelo_carregado = pickle.load(f)
print(modelo_carregado)
print(modelo_carregado.acuracia) # 0.94
Atenção: nunca carregue arquivos .pkl de fontes não confiáveis — o pickle pode executar código arbitrário durante a desserialização.
Exemplo Completo: Sistema de Log
import json
from pathlib import Path
from datetime import datetime
from enum import Enum
class Nivel(str, Enum):
DEBUG = "DEBUG"
INFO = "INFO"
AVISO = "AVISO"
ERRO = "ERRO"
CRITICO = "CRITICO"
class Logger:
def __init__(self, nome: str, pasta: str = "logs"):
self.nome = nome
self.pasta = Path(pasta)
self.pasta.mkdir(exist_ok=True)
data_hoje = datetime.now().strftime("%Y-%m-%d")
self._arquivo_txt = self.pasta / f"{nome}_{data_hoje}.log"
self._arquivo_json = self.pasta / f"{nome}_{data_hoje}.jsonl"
def _registrar(self, nivel: Nivel, mensagem: str, **extras):
agora = datetime.now()
entrada = {
"timestamp": agora.isoformat(),
"nivel": nivel.value,
"logger": self.nome,
"mensagem": mensagem,
**extras
}
# Formato legível para .log
linha_txt = (f"[{agora.strftime('%H:%M:%S')}] "
f"[{nivel.value:7}] "
f"[{self.nome}] {mensagem}")
if extras:
linha_txt += f" | {extras}"
with open(self._arquivo_txt, "a", encoding="utf-8") as f:
f.write(linha_txt + "\n")
# Formato estruturado para .jsonl (JSON Lines)
with open(self._arquivo_json, "a", encoding="utf-8") as f:
f.write(json.dumps(entrada, ensure_ascii=False) + "\n")
def debug(self, msg, **extras):
self._registrar(Nivel.DEBUG, msg, **extras)
def info(self, msg, **extras):
self._registrar(Nivel.INFO, msg, **extras)
def aviso(self, msg, **extras):
self._registrar(Nivel.AVISO, msg, **extras)
def erro(self, msg, **extras):
self._registrar(Nivel.ERRO, msg, **extras)
def ler_logs(self, nivel: Nivel = None) -> list:
"""Lê e filtra logs do arquivo JSONL."""
if not self._arquivo_json.exists():
return []
logs = []
for linha in self._arquivo_json.read_text(encoding="utf-8").splitlines():
entrada = json.loads(linha)
if nivel is None or entrada["nivel"] == nivel.value:
logs.append(entrada)
return logs
logger = Logger("sistema")
logger.info("Aplicação iniciada", versao="2.1.0")
logger.debug("Conectando ao banco", host="localhost", porta=5432)
logger.info("Usuário autenticado", usuario_id=42)
logger.aviso("Tentativa de login falhou", tentativas=3)
logger.erro("Falha na conexão com o banco", codigo=500)
print("\n=== Logs de ERRO ===")
for log in logger.ler_logs(Nivel.ERRO):
print(f" {log['timestamp']} — {log['mensagem']}")
print(f"\n=== Total de logs: {len(logger.ler_logs())} ===")
Resumo
open()comwithé a forma correta de abrir arquivos — fecha automaticamente- Sempre especifique
encoding="utf-8"para arquivos de texto - Para arquivos grandes, itere linha por linha em vez de usar
read()inteiro pathlib.Pathé a forma moderna e multiplataforma de manipular caminhoscsv.DictWriterecsv.DictReadersimplificam trabalho com arquivos tabularesjson.dump/loadserializa entre dicionários Python e arquivos JSONpickleserializa objetos Python arbitrários — use apenas com fontes confiáveis- JSON Lines (
.jsonl) é ideal para logs estruturados — um objeto JSON por linha
Referências e Leituras Complementares
- Leitura e escrita de arquivos — tutorial oficial — https://docs.python.org/3/tutorial/inputoutput.html
- pathlib — caminhos orientados a objetos — https://docs.python.org/3/library/pathlib.html
- Módulo csv — https://docs.python.org/3/library/csv.html
- Módulo json — https://docs.python.org/3/library/json.html
- Módulo pickle — https://docs.python.org/3/library/pickle.html
- BEAZLEY, David; JONES, Brian K. Python Cookbook. 3. ed. O'Reilly Media, 2013. Cap. 5 — receitas avançadas para arquivos e I/O.
- SWEIGART, Al. Automate the Boring Stuff with Python. 2. ed. No Starch Press, 2019. Cap. 8 e 9 — leitura, escrita e organização de arquivos com foco prático.
- MATTHES, Eric. Python Crash Course. 3. ed. No Starch Press, 2023. Cap. 10 — arquivos e exceções combinados.