Small files can be read or written in one call, without boilerplate.
For small and medium files, Path has one-call helpers:
p.read_text(encoding="utf-8")returns the whole file as a str.p.write_text(text, encoding="utf-8")creates or overwrites the file and returns the number of characters written.p.read_bytes()andp.write_bytes(data)do the same for binary data.
Each call opens and closes the file for you. Always pass encoding= for text: the default is the locale encoding, which differs between machines (Python 3.15 will switch to UTF-8 by default). read_text in 3.13 also accepts newline=.
For large files, or to process line by line, use p.open(), which takes the same arguments as the built-in open:
with p.open(encoding="utf-8") as f:
for line in f:
...write_text doesn't create missing parent directories; call p.parent.mkdir(parents=True, exist_ok=True) first. To append, use p.open("a"); there is no append_text.
read_text loads everything into memory and decodes it at once. That's ideal for config files and templates, but avoid it for multi-gigabyte logs.
Example
from pathlib import Path
out = Path("build") / "hello.txt"
out.parent.mkdir(parents=True, exist_ok=True)
print(out.write_text("héllo\nworld\n", encoding="utf-8")) # 12
print(out.read_text(encoding="utf-8").splitlines()) # ['héllo', 'world']
print(len(out.read_bytes())) # 13 (é is 2 bytes in UTF-8)
with out.open("a", encoding="utf-8") as f: # append
f.write("again\n")
with out.open(encoding="utf-8") as f:
print(sum(1 for _ in f)) # 3Remember
read_text/write_texthandle open and close in one call- Always pass
encoding="utf-8"for text files - Use
p.open()for large files, streaming or appending
Watch out for
- Calling
write_texton a path whose folder doesn't exist yet; it raises FileNotFoundError.