Chapter 24, Basic
Files and pathlib
Reading and writing files is the first time your program touches the outside world. I show the safe way: `with`, explicit encoding, and `pathlib`.
Code for this chapter: basico/cap24_arquivos.py
Open with with
The with ensures that the file is closed, even if an error occurs in the middle. I always pass encoding="utf-8" explicitly:
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
Why specify the encoding
If you do not specify the encoding, Python uses the system default. On Windows, this historically was not UTF-8, and the code that worked on your Mac broke with accents on a colleague's machine. Python 3.15 now uses UTF-8 as the default (PEP 686), but earlier versions still depend on the system, so the rule still applies: always explicit.
Opening modes
| Mode | Effect | Does it create the file? |
|---|---|---|
"r" | Reading (default). Fails if it does not exist | No |
"w" | Writing. Deletes the existing content | Yes |
"a" | Appends to the end | Yes |
"x" | Exclusive creation. Fails if it already exists | Yes |
"b" | Appended to others for binary mode ("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
Read line by line
read() ) loads the entire file into memory. For large files, iterate through the file with for: Python reads one line at a time:
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
Building paths with text ("pasta/" + nome) breaks between operating systems. The pathlib treats paths as objects, with the operator / and ready methods:
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
Common errors
The most common error is FileNotFoundError. And almost always the reason is the current directory: a relative path like "dados/entrada.txt" is resolved from the folder where you executed the command, not from the script's folder. To locate files next to the script, start from __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
Exercise 1
Count lines and words
Write estatisticas(caminho) that returns (linhas, palavras) in a file, reading one line at a time.