File I/O & DataLesson 1 of 2
File Operations
File handling in Python is built in and pleasantly synchronous. The with statement (a context manager) opens a file and guarantees it is closed when the block ends, even if an error occurs. No more forgetting to call close().
Pathlib is Python's modern path library. Instead of gluing strings together, you use the / operator: Path("data") / "file.txt". Paths are objects with useful methods and properties: .exists(), .read_text(), .write_text(), .suffix, .stem, .parent, and .glob().
Compared to Node's fs module, there is no callback-vs-promise-vs-sync decision to make. Reading a file is two lines: open it with with, then call .read(), or iterate over the file object to process it line by line.
Encoding needs your attention. open() does NOT default to UTF-8 everywhere: it uses the operating system's preferred encoding, which is UTF-8 on macOS and Linux but often cp1252 on Windows. Python 3.15 switches the default to UTF-8 on every platform (PEP 686), but until your code only runs on 3.15+, always pass encoding="utf-8" when you open text files. This prevents the classic "works on my Mac, crashes on Windows" UnicodeDecodeError.
Build paths with pathlib, not string concatenation. Python on Windows actually accepts forward slashes, so data + '/' + file.txt usually works, but string joining makes it easy to end up with doubled or missing separators, and you lose all the Path methods. Path("data") / "file.txt" (or os.path.join) is correct on every operating system.
Quick reference
| JavaScript | Python | Note |
|---|---|---|
| fs.readFileSync('f', 'utf8') | Path('f').read_text(encoding='utf-8') | Pass the encoding explicitly |
| fs.writeFileSync('f', data) | Path('f').write_text(data, encoding='utf-8') | Or open('f', 'w') |
| fs.appendFileSync('f', data) | open('f', 'a') | Mode a appends |
| path.join(a, b) | Path(a) / b | / operator on Path |
| path.extname('f.txt') | Path('f.txt').suffix | .suffix property |
| fs.existsSync('f') | Path('f').exists() | Path method |
| fs.globSync('*.py') (Node 22+) | Path('.').glob('*.py') | Built into pathlib |
Side by side
// Node.js
const fs = require('fs');
const path = require('path');
const data = fs.readFileSync('file.txt', 'utf8');
fs.writeFileSync('out.txt', 'hello');
fs.existsSync('file.txt');
path.join(__dirname, 'data', 'file.txt');
path.extname('file.txt');# Python
# Read the whole file
with open("file.txt", encoding="utf-8") as f:
data = f.read()
# Or iterate lines (memory efficient)
with open("file.txt", encoding="utf-8") as f:
for line in f:
print(line.strip())
# Write ("w" overwrites, "a" appends)
with open("out.txt", "w", encoding="utf-8") as f:
f.write("hello")
# pathlib (modern paths)
from pathlib import Path
p = Path("data") / "subdir" / "file.txt"
p.exists()
p.suffix # '.txt'
p.stem # 'file'
p.parent # Path('data/subdir')
p.read_text(encoding="utf-8") # read shortcut
p.write_text("hi", encoding="utf-8") # write shortcut
for f in Path(".").glob("*.py"):
print(f)Exercise
Real Python, running in your browserWrite Python code that:
Ctrl + Enter runCtrl + Shift + Enter checkTab indentEsc then Tab to leave the editorCtrl + / comment