Arquivos são só strings com um caminho
A maioria dos programas eventualmente precisa ler ou escrever um arquivo — configs, dados de usuário, logs, exportações CSV, pequenos caches. O Python mantém isso simples com uma função embutida, open(), mais um bloco with para garantir que as coisas fechem limpas.
Vamos passar pelos casos comuns.
Lendo um arquivo inteiro
A leitura mais simples:
with open("notes.txt") as f:
contents = f.read()
print(contents)
open("notes.txt") abre o arquivo para leitura (padrão). O bloco with significa que o Python vai fechar o arquivo quando você sai do bloco — mesmo se uma exceção é lançada. Uma vez fechado, você não pode mais usar f; o texto vive em contents.
contents é uma única string contendo o arquivo inteiro. Tudo bem para arquivos pequenos; ruim para um log de 2 GB.
Lendo linha por linha
Para arquivos maiores, itere em vez de ler tudo para a memória:
with open("big.log") as f:
for line in f:
if "ERROR" in line:
print(line.strip())
Cada iteração produz uma linha incluindo a quebra de linha final — por isso .strip() aparece com tanta frequência. Se quer uma lista de linhas, f.readlines() faz isso, mas geralmente a iteração direta é o que você quer.
Escrevendo um arquivo
Para escrever, passe o modo como segundo argumento:
with open("output.txt", "w") as f:
f.write("first line\n")
f.write("second line\n")
Duas coisas para notar:
"w"sobrescreve. Seoutput.txtjá existe, o conteúdo dele sumiu no momento em queopenroda.- Você adiciona as quebras de linha.
f.write("hello")escreve exatamente esses cinco caracteres — sem newline no fim.
Para adicionar em vez de sobrescrever:
with open("output.txt", "a") as f:
f.write("another line\n")
Você também pode alimentar várias linhas de uma vez com writelines:
lines = ["a\n", "b\n", "c\n"]
with open("letters.txt", "w") as f:
f.writelines(lines)
Mesma regra: você coloca as quebras de linha.
print para um arquivo
print tem um argumento file, que é um jeito fácil de escrever sem newlines manuais:
with open("log.txt", "w") as f:
print("started", file=f)
print("finished", file=f)
Cada print escreve os argumentos mais uma quebra de linha no fim. Para saída casual, muitas vezes é a forma mais gentil.
Modo texto vs binário
Por padrão, open está em modo texto. O Python decodifica bytes em strings (usando UTF-8 por padrão em plataformas modernas) e cuida da tradução de quebras de linha.
Para imagens, PDFs, arquivos compilados ou qualquer coisa que não é texto, abra em modo binário adicionando "b" ao modo:
with open("image.png", "rb") as f:
data = f.read()
print(len(data)) # number of bytes
with open("image_copy.png", "wb") as f:
f.write(data)
Em modo binário, você recebe objetos bytes em vez de str, e o Python não toca em quebras de linha.
Especificando encoding
Para arquivos de texto, seja explícito sobre encoding. UTF-8 é quase sempre certo em 2026:
with open("notes.txt", encoding="utf-8") as f:
contents = f.read()
Se você está lidando com arquivos antigos de uma empresa só Windows, pode ver cp1252 ou latin-1. Chutar errado te dá caracteres embaralhados ou um UnicodeDecodeError.
pathlib: o jeito moderno de lidar com caminhos
O módulo pathlib da biblioteca padrão te dá uma API mais ergonômica do que strings cruas:
from pathlib import Path
path = Path("notes.txt")
# Simple read and write.
contents = path.read_text(encoding="utf-8")
path.write_text("new contents\n", encoding="utf-8")
# Build paths without worrying about / vs \.
data_dir = Path("data")
log_path = data_dir / "today.log"
print(log_path)
print(log_path.exists())
print(log_path.suffix) # ".log"
print(log_path.stem) # "today"
print(log_path.parent) # "data"
Path.read_text() e write_text() são atalhos para o padrão with open(...) as f quando você só quer ler e escrever de uma vez. Para iteração linha por linha, você ainda usa open ou path.open().
Um pequeno exemplo de ponta a ponta
Ler uma lista de itens de um arquivo, filtrar e escrever o resultado em outro:
from pathlib import Path
source = Path("items.txt")
destination = Path("filtered.txt")
items = source.read_text().splitlines()
kept = [item for item in items if item and not item.startswith("#")]
destination.write_text("\n".join(kept) + "\n")
print(f"Kept {len(kept)} items out of {len(items)}")
splitlines() é o companheiro orientado a linha do join. Divide em quebras de linha sem mantê-las — útil quando você vai rejuntar as partes mesmo.
Quando as coisas dão errado
Abrir um arquivo que não existe lança FileNotFoundError. Tentar ler um arquivo sem permissão lança PermissionError. Os dois são subclasses de OSError, que por sua vez é subclasse de Exception — vamos falar de tratamento apropriado de exceções na próxima página.
Por enquanto, uma prévia rápida do que tratamento de erro parece:
from pathlib import Path
path = Path("maybe.txt")
try:
contents = path.read_text()
except FileNotFoundError:
print("File doesn't exist — starting fresh.")
contents = ""
print(repr(contents))
Hábitos principais
- Sempre use
with open(...)em vez deopenpuro + close manual. - Sempre passe
encoding=para arquivos de texto; UTF-8 por padrão. - Itere arquivos grandes linha por linha; não chame
.read()neles inteiros. - Para caminhos e padrões comuns de leitura/escrita, use
pathlib— vai te poupar muita ginástica de string.
Na sequência: JSON. A maioria dos arquivos de texto do mundo real que você lê não são linhas simples — são estruturados, e JSON é o formato mais comum. Os mesmos hábitos de with open(...) se carregam direto.
Perguntas frequentes
Como leio um arquivo em Python?
Use open() com a instrução with, que fecha o arquivo automaticamente quando você termina. with open('file.txt') as f: contents = f.read() lê o arquivo inteiro numa string. Para linha por linha, percorra o objeto de arquivo diretamente: for line in f:.
Qual a diferença entre os modos 'r', 'w' e 'a' do open?
'r' é leitura (padrão). 'w' é escrita — cria o arquivo ou trunca se existe. 'a' é append — adiciona ao fim do arquivo sem apagar o que está lá. Adicione 'b' para modo binário ou '+' para leitura+escrita.
Por que usar with open em vez de open() puro?
with open em vez de open() puro?A instrução with garante que o arquivo fecha mesmo se um erro acontece no meio. Sem with, você tem que chamar .close() você mesmo e lembrar em caminhos de erro. with é mais seguro e menos código.