Capítulo 24, Básico
Arquivos e pathlib
Ler e gravar arquivos é a primeira vez que o seu programa toca o mundo de fora. Eu mostro o jeito seguro: `with`, codificação explícita e `pathlib`.
Código deste capítulo: basico/cap24_arquivos.py
Abrir com with
O with garante que o arquivo seja fechado, mesmo que ocorra um erro no meio. Eu sempre passo encoding="utf-8" de forma explícita:
with open("notas.txt", "w", encoding="utf-8") as arquivo:
arquivo.write("primeira linha\n")
arquivo.write("segunda linha com acentuação\n")
with open("notas.txt", "r", encoding="utf-8") as arquivo:
conteudo = arquivo.read()
print(conteudo)
with open("notas.txt", "a", encoding="utf-8") as arquivo:
arquivo.write("terceira linha\n")
primeira linha
segunda linha com acentuação
Por que dizer o encoding
Se você não informa a codificação, o Python usa a padrão do sistema. No Windows, isso historicamente não era UTF-8, e o código que funcionava no seu Mac quebrava com acentos na máquina de um colega. O Python 3.15 passa a usar UTF-8 como padrão (PEP 686), mas versões anteriores continuam dependendo do sistema, então a regra continua valendo: sempre explícito.
Modos de abertura
| Modo | Efeito | Cria o arquivo? |
|---|---|---|
"r" | Leitura (padrão). Falha se não existir | Não |
"w" | Escrita. Apaga o conteúdo existente | Sim |
"a" | Acrescenta ao final | Sim |
"x" | Criação exclusiva. Falha se já existir | Sim |
"b" | Acrescentado aos demais para modo binário ("rb", "wb") |
try:
with open("notas.txt", "x", encoding="utf-8") as arquivo:
arquivo.write("não vai acontecer")
except FileExistsError:
print("notas.txt já existe, o modo x recusou")
notas.txt já existe, o modo x recusou
Ler linha por linha
read() carrega o arquivo inteiro na memória. Para arquivos grandes, percorra o arquivo com for: o Python lê uma linha por vez:
with open("notas.txt", encoding="utf-8") as arquivo:
for numero, linha in enumerate(arquivo, start=1):
print(numero, linha.rstrip("\n"))
1 primeira linha
2 segunda linha com acentuação
3 terceira linha
pathlib
Montar caminhos com texto ("pasta/" + nome) quebra entre sistemas operacionais. O pathlib trata caminhos como objetos, com o operador / e métodos prontos:
from pathlib import Path
pasta = Path("saida")
pasta.mkdir(exist_ok=True)
arquivo = pasta / "relatorio.txt"
arquivo.write_text("total: 42\n", encoding="utf-8")
print(arquivo.read_text(encoding="utf-8").strip())
print(arquivo.name, arquivo.stem, arquivo.suffix, arquivo.parent)
print(arquivo.exists(), (pasta / "nao_existe.txt").exists())
for item in sorted(pasta.glob("*.txt")):
print(item)
total: 42
relatorio.txt relatorio .txt saida
True False
saida/relatorio.txt
Erros comuns
O erro mais comum é FileNotFoundError. E quase sempre o motivo é o diretório atual: um caminho relativo como "dados/entrada.txt" é resolvido a partir da pasta onde você executou o comando, não da pasta do script. Para localizar arquivos ao lado do script, parta de __file__:
try:
open("nao_existe.txt", encoding="utf-8")
except FileNotFoundError as erro:
print(erro)
base = Path(__file__).parent
print((base / "dados").name)
[Errno 2] No such file or directory: 'nao_existe.txt'
dados
Exercício 1
Contar linhas e palavras
Escreva estatisticas(caminho) que devolva (linhas, palavras) de um arquivo, lendo uma linha por vez.