💻 Exemplos: Capítulo 12: Manipulação de Arquivos (Texto, CSV, JSON) e Context Managers (with)
Especialização em Sistemas com Python 3.12+ • Capítulo 012
🎯 Demonstração Prática: Pipeline de ETL de Arquivos com Escrita Atômica e Context Managers
O exemplo abaixo implementa um pipeline de extração, transformação e carga (ETL) no sistema de arquivos:
- Navegação orientada a objetos com
pathlib.Path. - Gerenciador de contexto customizado com
@contextmanagerpara telemetria de I/O. - Leitura e parsing de dados brutos tabulares em CSV via
csv.DictReader(..., delimiter=";"). - Escrita atômica resiliente com arquivo temporário e
Path.replace(), prevenindo corrupção em disco. - Exportação final em JSON com indentação padronizada e codificação UTF-8 explícita.
"""
demonstracao_arquivos_e_contexto.py
Pipeline de Processamento CSV/JSON com pathlib.Path, Context Managers e Escrita Atômica.
Compatível com Python 3.12+.
"""
from __future__ import annotations
from contextlib import contextmanager
import csv
from decimal import Decimal, ROUND_HALF_EVEN
import json
import os
from pathlib import Path
import time
from typing import Any, Iterator
# ==============================================================================
# 1. GERENCIADOR DE CONTEXTO CUSTOMIZADO PARA TELEMETRIA DE I/O
# ==============================================================================
@contextmanager
def monitorar_io(nome_etapa: str) -> Iterator[None]:
"""Mede e registra o tempo de processamento em operações de disco."""
t_inicio = time.perf_counter()
print(f" [I/O INÍCIO] {nome_etapa}...")
try:
yield
finally:
t_fim = time.perf_counter()
duracao_ms = (t_fim - t_inicio) * 1000
print(f" [I/O CONCLUÍDO] {nome_etapa} finalizado em {duracao_ms:.3f} ms.")
# ==============================================================================
# 2. GRAVAÇÃO ATÔMICA SEGURA DE ARQUIVOS
# ==============================================================================
def gravar_json_atomicamente(caminho_final: Path, dados: dict[str, Any]) -> None:
"""
Grava os dados em arquivo temporário com flush físico e renomeia atomicamente.
Elimina o risco de corrupção caso o processo seja interrompido abruptamente.
"""
caminho_final.parent.mkdir(parents=True, exist_ok=True)
caminho_temp = caminho_final.with_suffix(".tmp")
with caminho_temp.open(mode="w", encoding="utf-8") as f:
json.dump(dados, f, indent=2, ensure_ascii=False)
f.flush()
os.fsync(f.fileno()) # Força a gravação física no hardware do disco
# Operação atômica no sistema de arquivos
caminho_temp.replace(caminho_final)
# ==============================================================================
# 3. PIPELINE DE ETL (CSV -> TRANSFORMAÇÃO -> JSON)
# ==============================================================================
def executar_pipeline_vendas(caminho_csv: Path, caminho_json: Path) -> dict[str, Any]:
relatorio_consolidado: dict[str, Any] = {
"arquivo_origem": caminho_csv.name,
"total_registros": 0,
"faturamento_por_departamento": {},
"valor_total_faturado": "0.00"
}
faturamento_dept: dict[str, Decimal] = {}
faturamento_global = Decimal("0.00")
with monitorar_io(f"Leitura e parsing do CSV '{caminho_csv.name}'"):
with caminho_csv.open(mode="r", encoding="utf-8") as arquivo_entrada:
leitor = csv.DictReader(arquivo_entrada, delimiter=";")
for linha in leitor:
departamento = linha["departamento"].strip()
valor = Decimal(linha["valor"].replace(",", "."))
faturamento_dept[departamento] = faturamento_dept.get(departamento, Decimal("0.00")) + valor
faturamento_global += valor
relatorio_consolidado["total_registros"] += 1
# Formatação contábil para saída
relatorio_consolidado["faturamento_por_departamento"] = {
dept: f"R$ {val.quantize(Decimal('0.01'), ROUND_HALF_EVEN):,.2f}"
for dept, val in faturamento_dept.items()
}
relatorio_consolidado["valor_total_faturado"] = f"R$ {faturamento_global.quantize(Decimal('0.01'), ROUND_HALF_EVEN):,.2f}"
with monitorar_io(f"Gravação atômica do consolidado JSON '{caminho_json.name}'"):
gravar_json_atomicamente(caminho_json, relatorio_consolidado)
return relatorio_consolidado
# ==============================================================================
# 4. EXECUÇÃO DEMONSTRATIVA
# ==============================================================================
if __name__ == "__main__":
diretorio_trabalho = Path("temp_pipeline_demo")
arquivo_csv_teste = diretorio_trabalho / "transacoes_filial.csv"
arquivo_json_saida = diretorio_trabalho / "auditoria_consolidada.json"
print("=" * 80)
print(" PIPELINE DE ARQUIVOS ROBUSTO COM PATHLIB E GRAVAÇÃO ATÔMICA")
print("=" * 80)
# 1. Criação do arquivo de teste com CSV em UTF-8
diretorio_trabalho.mkdir(parents=True, exist_ok=True)
conteudo_csv_bruto = (
"id_transacao;departamento;valor;data\n"
"TX-101;Eletrônicos;4500.50;2026-09-28\n"
"TX-102;Mobiliário Corporativo;12800.00;2026-09-28\n"
"TX-103;Eletrônicos;3200.00;2026-09-28\n"
"TX-104;Suprimentos de TI;890.90;2026-09-28\n"
"TX-105;Mobiliário Corporativo;1500.00;2026-09-28\n"
)
arquivo_csv_teste.write_text(conteudo_csv_bruto, encoding="utf-8")
print(f">> Arquivo de entrada simulado gerado em: {arquivo_csv_teste}")
print("-" * 80)
# 2. Execução do pipeline
resultado = executar_pipeline_vendas(arquivo_csv_teste, arquivo_json_saida)
print("-" * 80)
print("Resultado da Consolidação Contábil:")
print(f"Total de Linhas Processadas : {resultado['total_registros']}")
print(f"Faturamento Global Apurado : {resultado['valor_total_faturado']}")
print("\nFaturamento por Departamento:")
for dept, subtotal in resultado["faturamento_por_departamento"].items():
print(f" * {dept:<26} : {subtotal}")
print("\n" + "-" * 80)
print(f"Conteúdo Gravado em '{arquivo_json_saida.name}' via Escrita Atômica:")
print(arquivo_json_saida.read_text(encoding="utf-8"))
# Limpeza de arquivos de teste temporários
arquivo_csv_teste.unlink()
arquivo_json_saida.unlink()
diretorio_trabalho.rmdir()
print("-" * 80)
print(">> Limpeza de ambiente concluída com sucesso.")
print("=" * 80)