Capítulo 12: Manipulação de Arquivos (Texto, CSV, JSON) e Context Managers (with)
Especialização em Sistemas com Python & POO com Type Hints • Capítulo 12
🗺️ Mapa Conceitual do Tópico
flowchart TD
subgraph PATHLIB["Sistema de Arquivos com pathlib.Path (PEP 428)"]
PATH["Path('dados/relatorio.json')\nNavegação com Operador / · .glob() · .rglob()"]
PROPS[".stem · .suffix · .parent · .is_file()"]
MKDIR[".mkdir(parents=True, exist_ok=True)"]
end
subgraph PROTOCOL["Protocolo de Gerenciamento de Contexto"]
WITH["with open(..., encoding='utf-8') as f:"]
ENTER["__enter__() -> Adquire Descritor do Sistema Operacional"]
EXIT["__exit__(exc_type, exc_val, tb) -> Liberação Incondicional"]
CTXLIB["@contextlib.contextmanager (Geradores de Contexto)"]
end
subgraph FORMATS["Formatos Corporativos e Escrita Atômica"]
CSV_M["Módulo csv\nDictReader & DictWriter com newline=''"]
JSON_M["Módulo json\ndump/load (Disco) vs dumps/loads (RAM)"]
ATOMIC["Escrita Atômica de Arquivos\nGravação em .tmp + Renomeação Atômica (.replace())"]
end
PATHLIB --> PROTOCOL
PROTOCOL --> FORMATS
style PATHLIB fill:#ede7f6,stroke:#512da8,stroke-width:2px
style PROTOCOL fill:#e1f5fe,stroke:#0288d1,stroke-width:2px
style FORMATS fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px
📁 1. O Módulo pathlib.Path (PEP 428) no Windows e Linux
Substituindo o antigo módulo procedural os.path, o pathlib.Path oferece uma API orientada a objetos fluida para navegação e inspeção no sistema de arquivos, tratando automaticamente as diferenças de barras entre Windows (\) e sistemas Unix (/).
Operações Essenciais de Engenharia
from pathlib import Path
# Composição semântica de caminhos com sobrecarga do operador /:
diretorio_base: Path = Path.cwd() / "data" / "relatorios"
arquivo_alvo: Path = diretorio_base / "2026_auditoria.json"
# Criação recursiva e idempotente de diretórios (semelhante ao mkdir -p):
diretorio_base.mkdir(parents=True, exist_ok=True)
# Inspeção semântica de componentes do caminho:
print(f"Nome completo : {arquivo_alvo.name}") # 2026_auditoria.json
print(f"Nome puro : {arquivo_alvo.stem}") # 2026_auditoria
print(f"Extensão : {arquivo_alvo.suffix}") # .json
print(f"Pasta Pai : {arquivo_alvo.parent}") # data/relatorios
# Varredura em profundidade com rglob:
arquivos_csv: list[Path] = list(diretorio_base.rglob("*.csv"))
⚠️ A Armadilha de Codificação do Windows: No Windows, a função
open()sem argumento de encoding utiliza o padrão legado ANSI (CP1252), corrompendo acentuações (ç,ã). Em aplicações profissionais, declare sempreencoding="utf-8".
🔒 2. O Protocolo de Gerenciador de Contexto (with)
Em sistemas operacionais, arquivos abertos consom descritores de arquivo (File Descriptors / Handles), limitados por processo. Esquecer de fechar um arquivo causa bloqueios no Windows e esgotamento de handles no Linux. A instrução with garante liberação imediata via protocolo:
__enter__(): Executado antes do corpo do bloco. Abre o recurso e vincula a variável de saída (as arquivo).__exit__(exc_type, exc_val, exc_tb): Executado incondicionalmente ao sair do bloco, mesmo que ocorra uma exceção grave ousys.exit(). Libera os buffers e fecha o descritor no SO.
Criando Gerenciadores de Contexto com contextlib
from contextlib import contextmanager
import time
from typing import Iterator
@contextmanager
def cronometrar_operacao(rotulo: str) -> Iterator[None]:
inicio = time.perf_counter()
try:
yield # Entrega controle ao corpo do with
finally:
fim = time.perf_counter()
print(f"[{rotulo}] Duração da I/O: {(fim - inicio) * 1000:.2f} ms")
📊 3. Manipulação de CSV e JSON Corporativos
Processamento Estruturado com csv.DictReader e csv.DictWriter
Para evitar erros de índice por coluna, utilize leitores e escritores baseados em dicionários:
import csv
from pathlib import Path
def exportar_csv_seguro(caminho: Path, linhas: list[dict[str, object]]) -> None:
# newline="" é OBRIGATÓRIO no Windows para evitar linhas em branco duplicadas
with caminho.open(mode="w", newline="", encoding="utf-8") as f:
colunas = list(linhas[0].keys())
escritor = csv.DictWriter(f, fieldnames=colunas, delimiter=";")
escritor.writeheader()
escritor.writerows(linhas)
Serialização JSON com Tratamento de Caracteres Especiais
import json
# Gravação formatada com acentos preservados:
with caminho.open(mode="w", encoding="utf-8") as f:
json.dump(dados, f, indent=2, ensure_ascii=False)
🛡️ 4. Padrão de Engenharia: Gravação Atômica de Arquivos
Em servidores corporativos, salvar arquivos sobrescrevendo diretamente o arquivo original (open("dados.json", "w")) é arriscado: uma interrupção inesperada (queda de energia, SIGKILL pelo orquestrador de pods) deixará o arquivo vazio ou parcialmente corrompido.
O Padrão de Escrita Atômica resolve isso em três etapas:
- Grava os novos dados em um arquivo temporário no mesmo sistema de arquivos (
relatorio.json.tmp). - Descarrega os buffers de I/O no disco físico (
f.flush(); os.fsync(f.fileno())). - Renomeia o temporário sobre o original via
Path.replace(), operação atômica em nível de sistema de arquivos no Windows e Linux.