Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Werkboek — Hoofdstuk 8: Bestanden lezen en schrijven

Let op: alle programmacode schrijf je in het Engels (zoals in het boek). De uitleg en opdrachten zijn in het Nederlands.

Doel van dit hoofdstuk

  • Veilig werken met with open(...) en tekst‐encodering (encoding="utf-8").
  • Leespatronen voor tekst: read(), regels itereren, readline(), read(n).
  • Schrijfpatronen: write, writelines, newlines en newline‑parameter.
  • Paden met pathlib.Path: paden samenstellen, directories maken, globben.
  • Binaire I/O (chunks), defensief werken en veelvoorkomende valkuilen.

Richtlijnen

  • Gebruik with voor alle bestandsoperaties.
  • Specificeer bij tekstbestanden encoding="utf-8" expliciet.
  • Gebruik pathlib.Path waar zinvol i.p.v. alleen stringpaden.
  • Voeg zelf \n toe bij write; print(..., file=f) voegt standaard een newline toe (tenzij end is aangepast).

Oefening 1 — Merge .txt bestanden Schrijf een script dat alle .txt‑bestanden in een gegeven directory samenvoegt tot all.txt. Zet tussen ieder bronbestand een lege regel. Gebruik pathlib.Path.glob("*.txt").

Oefening 2 — tail(path, n) Implementeer een functie tail(path: str | Path, n: int) -> list[str] die de laatste n regels van een tekstbestand teruggeeft (zonder trailing newlines). Efficiënt genoeg voor middelgrote bestanden (je mag het hele bestand inlezen en de laatste n regels nemen).

Oefening 3 — copy_file (binair) Schrijf copy_file(src: str | Path, dst: str | Path, chunk_size: int = 8192) -> None die binaire data kopieert in chunks. Gebruik rb/wb en een lus met read(chunk_size).

Oefening 4 — grep‑achtig filter (case‑insensitive) Schrijf een functie grep_ci(path: str | Path, needle: str) -> None die regels print die needle (case‑insensitive) bevatten. Open met errors="replace" zodat corrupte encodering niet crasht.

Oefening 5 — CSV lezen (naïef) en net printen Gegeven een CSV‑bestand items.csv met kolommen name,qty,price. Lees het naïef met split(',') (weet: dit is niet robuust voor echte CSV). Print dan een tabel met nette kolombreedtes en een grand total.

Oefening 6 — JSON schrijven en lezen Schrijf twee helpers:

  • write_config(path: Path, data: dict) -> None die JSON schrijft met ensure_ascii=False, indent=2.
  • read_config(path: Path) -> dict die leest en het dict teruggeeft. Schrijf een __main__‑blok dat een klein config‑dict schrijft en daarna weer leest en een veld print. Vang FileNotFoundError en json.JSONDecodeError met duidelijke meldingen.

Oefening 7 — Atomisch schrijven Schrijf een functie atomic_write_text(path: Path, text: str) -> None die eerst naar path.with_suffix(path.suffix + ".tmp") schrijft en daarna os.replace gebruikt om atomisch te vervangen. Voeg encoding toe.

Oefening 8 — Newline normalisatie Schrijf write_unix_newlines(path: Path, lines: list[str]) -> None die altijd Unix‑newlines (\n) schrijft, ongeacht platform. Gebruik newline='\n' bij open en writelines.

Oefening 9 — Safe read_text Schrijf safe_read_text(path: Path) -> str | None die de inhoud leest (utf‑8) of None teruggeeft bij FileNotFoundError of PermissionError, met een vriendelijke printmelding.

Oefening 10 — Directory listing met groottes Schrijf een script dat alle items in een directory print met hun type (file/dir) en voor files ook de grootte in bytes. Toon onderaan het totaal aantal files en het totale aantal bytes. Gebruik Path.iterdir().

Uitdaging (optioneel) — Mini To‑Do CLI met bestand Maak een klein CLI‑programma dat een tekstbestand todo.txt gebruikt in de huidige directory.

  • add <text> voegt een regel toe.
  • list toont genummerde regels.
  • done <n> markeert item n als gedaan door het te verwijderen of te prefixen met [x] (kies één en beschrijf in een comment je keuze). Gebruik with en encoding="utf-8"; onthoud dat het bestand niet hoeft te bestaan bij de eerste run.