Python

Leitura e Escrita de Arquivos Já leu

8 min de leitura

Leitura e Escrita de Arquivos
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.

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() com with é 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 caminhos
  • csv.DictWriter e csv.DictReader simplificam trabalho com arquivos tabulares
  • json.dump/load serializa entre dicionários Python e arquivos JSON
  • pickle serializa 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.
Comentários

Mais em Python

Decoradores e Metaprogramação
Decoradores e Metaprogramação

Decoradores s&atilde;o um dos recursos mais elegantes do Python. Eles permite...

Artigo 36 — Machine Learning com scikit-learn
Artigo 36 — Machine Learning com scikit-learn

Machine Learning é a capacidade de um sistema aprender padrões a partir de da...

Artigo 52 — Carreira: portfólio, GitHub, open source e o mercado Python
Artigo 52 — Carreira: portfólio, GitHub, open source e o mercado Python

Você chegou ao último artigo da série. Ao longo de 52 artigos e 9 módulos, pe...