Manipulação de arquivos: lendo e escrevendo texto
Trabalhar com arquivos de texto é uma das tarefas mais fundamentais na programação Python. Seja para processar logs, ler configurações, gerar relatórios ou persistir dados, dominar a leitura e escrita de arquivos é essencial. Neste artigo, você aprenderá desde a abertura segura de arquivos até boas práticas para evitar erros comuns.
1. Abrindo e fechando arquivos com open()
A função open() é a porta de entrada para manipular arquivos em Python. Ela recebe o caminho do arquivo e o modo de abertura como parâmetros principais.
Modos de abertura
| Modo | Descrição |
|---|---|
'r' |
Leitura (padrão). O arquivo deve existir. |
'w' |
Escrita. Cria um novo arquivo ou sobrescreve o existente. |
'a' |
Append. Adiciona conteúdo ao final do arquivo. |
'x' |
Criação exclusiva. Falha se o arquivo já existir. |
'r+' |
Leitura e escrita (sem truncar). |
'w+' |
Leitura e escrita (trunca o arquivo). |
Gerenciador de contexto with
A forma mais segura e recomendada de trabalhar com arquivos é usando o gerenciador de contexto with:
with open('exemplo.txt', 'r', encoding='utf-8') as arquivo:
conteudo = arquivo.read()
# O arquivo é fechado automaticamente ao sair do bloco
Sem o with, você precisaria chamar arquivo.close() manualmente, o que pode ser esquecido ou não executado em caso de exceções.
Encoding
Sempre especifique encoding='utf-8' ao abrir arquivos de texto. Isso evita problemas com caracteres acentuados e garante compatibilidade entre sistemas:
# Problema comum sem encoding
with open('dados.txt', 'r') as arquivo: # Pode gerar UnicodeDecodeError
dados = arquivo.read()
# Correto
with open('dados.txt', 'r', encoding='utf-8') as arquivo:
dados = arquivo.read()
2. Lendo arquivos de texto
Python oferece várias formas de ler o conteúdo de um arquivo, cada uma adequada a diferentes cenários.
Leitura completa
# read() - lê todo o conteúdo como string única
with open('poema.txt', 'r', encoding='utf-8') as f:
texto_completo = f.read()
print(texto_completo)
# readlines() - retorna lista de linhas
with open('poema.txt', 'r', encoding='utf-8') as f:
linhas = f.readlines()
print(f"O poema tem {len(linhas)} linhas")
Leitura linha por linha (eficiente para arquivos grandes)
# Iteração direta - não carrega tudo na memória
with open('grande_arquivo.txt', 'r', encoding='utf-8') as f:
for linha in f:
# Processa cada linha individualmente
if 'erro' in linha.lower():
print(f"Erro encontrado: {linha.strip()}")
Leitura parcial com read(n)
with open('arquivo.txt', 'r', encoding='utf-8') as f:
primeiros_100_caracteres = f.read(100)
print(primeiros_100_caracteres)
3. Escrevendo em arquivos de texto
Escrevendo com write() e writelines()
# write() - escreve uma string
with open('saida.txt', 'w', encoding='utf-8') as f:
f.write('Primeira linha\n')
f.write('Segunda linha\n')
# writelines() - escreve uma lista de strings (sem adicionar \n automaticamente)
linhas = ['Linha 1\n', 'Linha 2\n', 'Linha 3\n']
with open('saida.txt', 'w', encoding='utf-8') as f:
f.writelines(linhas)
Modo append ('a')
with open('log.txt', 'a', encoding='utf-8') as f:
f.write(f'{datetime.now()}: Nova entrada no log\n')
Controle de quebras de linha
Em Windows, as quebras de linha são \r\n, enquanto em Unix/Linux/macOS são \n. Python gerencia isso automaticamente no modo texto, mas ao escrever explicitamente, use \n:
with open('dados.txt', 'w', encoding='utf-8') as f:
f.write('linha1\nlinha2\nlinha3\n') # Python converte para \r\n no Windows
4. Manipulando caminhos e diretórios
Usando pathlib (moderno e recomendado)
from pathlib import Path
# Caminhos relativos e absolutos
caminho = Path('dados') / 'arquivo.txt'
caminho_absoluto = Path.home() / 'documentos' / 'relatorio.txt'
# Verificando existência
if caminho.exists():
print(f"{caminho} existe")
if caminho.is_file():
print(f"{caminho} é um arquivo")
# Criando diretórios automaticamente
caminho.parent.mkdir(parents=True, exist_ok=True)
Usando os.path (tradicional)
import os
# Verificando existência
if os.path.exists('arquivo.txt'):
print("Arquivo existe")
if os.path.isfile('arquivo.txt'):
print("É um arquivo regular")
# Criando diretórios
os.makedirs('dados/subdados', exist_ok=True)
5. Tratamento de erros comuns em arquivos
import os
def ler_arquivo_seguro(caminho):
try:
with open(caminho, 'r', encoding='utf-8') as f:
return f.read()
except FileNotFoundError:
print(f"Erro: Arquivo '{caminho}' não encontrado")
return None
except PermissionError:
print(f"Erro: Sem permissão para ler '{caminho}'")
return None
except IsADirectoryError:
print(f"Erro: '{caminho}' é um diretório, não um arquivo")
return None
# Exemplo de uso
conteudo = ler_arquivo_seguro('config.txt')
if conteudo:
print(conteudo)
Tratamento para criação exclusiva
try:
with open('novo_arquivo.txt', 'x', encoding='utf-8') as f:
f.write('Conteúdo inicial')
except FileExistsError:
print("Arquivo já existe! Use modo 'w' para sobrescrever")
6. Boas práticas e dicas essenciais
Sempre use with
Nunca use open() sem o gerenciador de contexto. O padrão correto é:
# ✅ Correto
with open('arquivo.txt', 'r') as f:
dados = f.read()
# ❌ Evite
f = open('arquivo.txt', 'r')
dados = f.read()
f.close() # Fácil de esquecer
Controle de buffer com flush()
Para garantir que os dados sejam escritos imediatamente (útil em logs):
with open('log.txt', 'a', encoding='utf-8') as f:
f.write('Dado crítico\n')
f.flush() # Força a escrita no disco
Leitura eficiente para arquivos grandes
Para arquivos muito grandes que não cabem na memória:
# Leitura em blocos de 1KB
def ler_em_partes(caminho, tamanho_bloco=1024):
with open(caminho, 'r', encoding='utf-8') as f:
while True:
bloco = f.read(tamanho_bloco)
if not bloco:
break
yield bloco
# Uso
for parte in ler_em_partes('gigante.txt'):
processar(parte) # Função que processa cada parte
Exemplo completo: processador de arquivo de configuração
from pathlib import Path
def processar_config(caminho_config):
config_path = Path(caminho_config)
# Verifica se o arquivo existe
if not config_path.exists():
print(f"Criando arquivo de configuração padrão: {config_path}")
config_path.parent.mkdir(parents=True, exist_ok=True)
with open(config_path, 'w', encoding='utf-8') as f:
f.write("# Configurações do sistema\n")
f.write("DEBUG=False\n")
f.write("PORT=8080\n")
return
# Lê e processa o arquivo existente
with open(config_path, 'r', encoding='utf-8') as f:
for linha in f:
linha = linha.strip()
if linha and not linha.startswith('#'):
chave, valor = linha.split('=', 1)
print(f"{chave}: {valor}")
# Uso
processar_config('config/sistema.conf')
Dominar a manipulação de arquivos em Python é um passo fundamental para qualquer desenvolvedor. Com as técnicas apresentadas aqui, você estará preparado para lidar desde pequenos arquivos de configuração até grandes volumes de dados de forma segura e eficiente.
Referências
- Documentação oficial: Leitura e escrita de arquivos — Guia completo da documentação Python sobre operações básicas de arquivos
- Real Python: Reading and Writing Files in Python — Tutorial abrangente com exemplos práticos e boas práticas
- Python.org: Gerenciadores de Contexto — Documentação oficial sobre o protocolo
withe gerenciadores de contexto - Pathlib - Manipulação de caminhos — Documentação oficial do módulo
pathlibpara manipulação moderna de caminhos - GeeksforGeeks: File Handling in Python — Tutorial detalhado com exemplos de tratamento de erros e modos de abertura
- W3Schools: Python File Handling — Referência rápida e interativa sobre operações de arquivos em Python