Path.read_text
read_text() opens, reads everything, and closes; write_text() creates or OVERWRITES the file. Always pass encoding="utf-8" — the default is the locale encoding, which differs between machines.
Common call
p.read_text(encoding='utf-8')
Returns
the whole file as str
Replaces
with open(p, encoding='utf-8') as f: f.read()
Watch out
write_text overwrites; there is no append mode
Path.read_text(encodingencoding — Text methods only. None means the locale encoding (locale.getencoding()); pass 'utf-8' explicitly.type: str | None · default: None=None, errorserrors — Text methods only: 'strict' (default), 'replace', 'ignore', 'surrogateescape' …type: str | None · default: None=None, newlinenewline — Text methods only (write 3.10+, read 3.13+): as in open(). None translates line endings; '' leaves them alone.type: str | None · default: None=None) / .write_text(data, encodingencoding — Text methods only. None means the locale encoding (locale.getencoding()); pass 'utf-8' explicitly.type: str | None · default: None=None, errorserrors — Text methods only: 'strict' (default), 'replace', 'ignore', 'surrogateescape' …type: str | None · default: None=None, newlinenewline — Text methods only (write 3.10+, read 3.13+): as in open(). None translates line endings; '' leaves them alone.type: str | None · default: None=None) / .read_bytes() / .write_bytes(data)
→ str | bytes | int
Demo
Live evaluation
write_text returns the number of characters written, not bytes.
Try:
Inputs
textstrtext to write
Code
from pathlib import Path p = Path('notes.txt') n = p.write_text('hello', encoding='utf-8') (n, p.read_text(encoding='utf-8'))
Result
(5, 'hello')
The count is in characters: 'crème brûlée' is 12 characters even though its UTF-8 encoding is 15 bytes. Reading a file that does not exist raises FileNotFoundError with errno 2 and the file name.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| data | str | bytes | yes | write_text: a str; write_bytes: bytes-like. Anything else is a TypeError. |
| encoding | str | None | no (None) | Text methods only. None means the locale encoding (locale.getencoding()); pass 'utf-8' explicitly. |
| errors | str | None | no (None) | Text methods only: 'strict' (default), 'replace', 'ignore', 'surrogateescape' … |
| newline | str | None | no (None) | Text methods only (write 3.10+, read 3.13+): as in open(). None translates line endings; '' leaves them alone. |
Return value
str | bytes | int — read_* return the content; write_* return the number of characters / bytes written.
Common patterns
Read lines without the newline characters
splitlines() handles \n, \r\n and a missing final newline.
from pathlib import Path lines = Path('names.txt').read_text(encoding='utf-8').splitlines()
Append instead of overwrite
write_text has no append mode; use open('a').
from pathlib import Path with Path('app.log').open('a', encoding='utf-8') as f: f.write('started\n')
Write atomically
Write to a temporary sibling, then replace() — readers never see half a file.
from pathlib import Path target = Path('config.json') tmp = target.with_suffix('.tmp') tmp.write_text(text, encoding='utf-8') tmp.replace(target)
Copy a file
Small files: bytes in, bytes out (shutil.copy for large ones or to keep metadata).
from pathlib import Path Path('copy.png').write_bytes(Path('logo.png').read_bytes())
Examples
1. Write then read
from pathlib import Path
p = Path('greeting.txt')
p.write_text('Hello, world', encoding='utf-8')
p.read_text(encoding='utf-8')
Returns
'Hello, world'2. write_text counts characters
from pathlib import Path
Path('menu.txt').write_text('crème', encoding='utf-8')
Returns
53. write_bytes counts bytes
from pathlib import Path
Path('menu.bin').write_bytes('crème'.encode('utf-8'))
Returns
64. read_bytes gives raw bytes
from pathlib import Path
p = Path('menu.txt')
p.write_text('crème', encoding='utf-8')
p.read_bytes()
Returns
b'cr\xc3\xa8me'5. write_text overwrites
from pathlib import Path
p = Path('log.txt')
p.write_text('first', encoding='utf-8')
p.write_text('second', encoding='utf-8')
p.read_text(encoding='utf-8')
Returns
'second'6. Line endings come back as \n
from pathlib import Path
p = Path('crlf.txt')
p.write_bytes(b'a\r\nb\r\n')
p.read_text(encoding='utf-8')
Returns
'a\nb\n'7. Missing file
from pathlib import Path
Path('nope.txt').read_text(encoding='utf-8')
Returns
FileNotFoundError: [Errno 2] No such file or directory: 'nope.txt'8. write_text wants str
from pathlib import Path
Path('n.txt').write_text(42)
Returns
TypeError: data must be str, not intPitfalls
1. Relying on the default encoding
Without encoding=, Python uses the locale encoding, so the same file can read differently on another machine. Decoding bytes that are not valid in the chosen encoding raises UnicodeDecodeError.
wrong codec
from pathlib import Path p = Path('menu.txt') p.write_text('crème', encoding='utf-8') p.read_text(encoding='ascii')
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 2: ordinal not in range(128)
encoding='utf-8'
from pathlib import Path p = Path('menu.txt') p.write_text('crème', encoding='utf-8') p.read_text(encoding='utf-8')
'crème'
2. Writing into a folder that does not exist
write_text does not create parent folders. mkdir(parents=True, exist_ok=True) the parent first.
no parent
from pathlib import Path try: Path('out/report.txt').write_text('ok', encoding='utf-8') except OSError as e: result = type(e).__name__ result
'FileNotFoundError'
create parents
from pathlib import Path p = Path('out/report.txt') p.parent.mkdir(parents=True, exist_ok=True) p.write_text('ok', encoding='utf-8') p.read_text(encoding='utf-8')
'ok'
3. Reading huge files at once
read_text loads the whole file into memory. Iterate over an open file for large logs.
all at once
from pathlib import Path p = Path('big.log') p.write_text('x\n' * 3, encoding='utf-8') len(p.read_text(encoding='utf-8').splitlines())
3
line by line
from pathlib import Path p = Path('big.log') p.write_text('x\n' * 3, encoding='utf-8') with p.open(encoding='utf-8') as f: count = sum(1 for _ in f) count
3
When to use
Use it
- Small and medium files you need in full (configs, templates, JSON, CSV under a few MB)
- Quick scripts and tests
Reach for something else
- Appending → p.open("a")
- Very large files or streams → iterate over p.open()
- Binary formats with structure → read_bytes plus a parser, or the format library
Notes
CPython impl
Path.read_text / write_text (Lib/pathlib/_local.py) call io.text_encoding(encoding) then PathBase.read_text / write_text, which use self.open(); read_bytes / write_bytes are inherited from PathBase in _abc.py
Line endings
Text mode with newline=None: '\r\n' and '\r' read back as '\n'; on write, '\n' becomes os.linesep — so a file written with write_text('a\n') is 3 bytes on Windows and 2 on Linux
Return value
write_text: characters written; write_bytes: bytes written
EncodingWarning
With python -X warn_default_encoding, calls without encoding= emit EncodingWarning
FAQ
Path('file.txt').read_text(encoding='utf-8'). It opens, reads and closes the file for you.