DE EN

File I/O & JSON

Reading and writing files, saving configurations, processing JSON data.

50 Min Mittel

Lernziele dieses Kapitels

  • You read and write files safely with with open()
  • You store and load Python data as JSON
  • You catch errors with try/except and make code robust
  • You save PyBuddy's configuration persistently

Reading and Writing Files

With with open() you open files safely. The with statement closes the file automatically — even if an error occurs. Never again forgotten close()!

  • 'r' — read (default)
  • 'w' — write (overwrites!)
  • 'a' — append
  • encoding='utf-8' — for umlauts
Python
# Datei schreiben
with open("notiz.txt", "w", encoding="utf-8") as f:
    f.write("Python ist cool!\n")
    f.write("Heute lerne ich File I/O.\n")

# Datei lesen
with open("notiz.txt", "r", encoding="utf-8") as f:
    inhalt = f.read()
    print(inhalt)

# Zeile für Zeile lesen
with open("notiz.txt", "r", encoding="utf-8") as f:
    for zeile in f:
        print(f"→ {zeile.strip()}")
Ausgabe
Python ist cool! Heute lerne ich File I/O. → Python ist cool! → Heute lerne ich File I/O.
Python vs. JavaScript — Das kennst du schon!

Du kennst bereits JavaScript aus dem JS-Quest. Hier ist der direkte Vergleich:

Python
with open('datei.txt', 'w') as f:
    f.write('Hallo')
JavaScript
const fs = require('fs');
fs.writeFileSync('datei.txt', 'Hallo');
Merke: Python: with open() is elegant and safe. JavaScript (Node.js): fs.writeFileSync() or Promises. Python's approach is shorter and more readable.

Processing JSON

JSON (JavaScript Object Notation) is the standard format for data on the web. Python has the json module built in: json.dump() saves, json.load() loads.

Python
import json

# Dictionary als JSON speichern
spieler = {
    "name": "PyKnight",
    "level": 5,
    "items": ["Schwert", "Schild"]
}

with open("spieler.json", "w", encoding="utf-8") as f:
    json.dump(spieler, f, indent=2, ensure_ascii=False)

# JSON laden
with open("spieler.json", "r", encoding="utf-8") as f:
    geladen = json.load(f)

print(geladen["name"])
print(f"Items: {geladen['items']}")
Ausgabe
PyKnight Items: ['Schwert', 'Schild']
Python vs. JavaScript — Das kennst du schon!

Du kennst bereits JavaScript aus dem JS-Quest. Hier ist der direkte Vergleich:

Python
import json
json.dump(daten, f, indent=2)
json.load(f)
JavaScript
const fs = require('fs');
fs.writeFileSync('daten.json', JSON.stringify(daten, null, 2));
JSON.parse(fs.readFileSync('daten.json'));
Merke: Python: json.dump() writes directly to a file. JavaScript: JSON.stringify() returns a string that you must save with fs.

Error Handling with try/except

Errors happen — especially with file access. With try/except you catch them and react gracefully, instead of letting the program crash.

Attention

Only catch errors you can actually handle. Never use an empty except: block without an error type!

Python
# Robuster Dateizugriff
try:
    with open("config.json", "r", encoding="utf-8") as f:
        config = json.load(f)
        print(f"Theme: {config['theme']}")
except FileNotFoundError:
    print("  config.json nicht gefunden. Erstelle Standard-Konfiguration.")
    config = {"theme": "dark", "sprache": "de"}
except json.JSONDecodeError:
    print(" config.json ist beschädigt!")
    config = {"theme": "dark"}

# Mehrere Fehlertypen
try:
    zahl = int(input("Zahl: "))
    ergebnis = 100 / zahl
    print(f"Ergebnis: {ergebnis}")
except ValueError:
    print(" Das war keine gültige Zahl!")
except ZeroDivisionError:
    print(" Division durch Null ist nicht erlaubt!")
Ausgabe
config.json nicht gefunden. Erstelle Standard-Konfiguration. Zahl: 0 Division durch Null ist nicht erlaubt!
Python vs. JavaScript — Das kennst du schon!

Du kennst bereits JavaScript aus dem JS-Quest. Hier ist der direkte Vergleich:

Python
try:
    with open('datei.txt') as f:
        data = f.read()
except FileNotFoundError:
    print('Nicht gefunden')
JavaScript
try {
    const data = fs.readFileSync('datei.txt', 'utf8');
} catch (err) {
    if (err.code === 'ENOENT') {
        console.log('Nicht gefunden');
    }
}
Merke: Both Python and JavaScript have try/catch (or try/except). Python distinguishes error types more cleanly, in JS you often check err.code.

CSV Files

CSV (Comma-Separated Values) is the standard format for table data. Python has the csv module built in, which handles parsing correctly — even with commas inside cells.

Python
import csv

# CSV schreiben
with open("noten.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.writer(f)
    writer.writerow(["Name", "Fach", "Note"])
    writer.writerow(["Anna", "Mathe", 1])
    writer.writerow(["Ben", "Englisch", 2])

# CSV lesen
with open("noten.csv", "r", encoding="utf-8") as f:
    reader = csv.reader(f)
    for row in reader:
        print(f"{row[0]:10} | {row[1]:10} | {row[2]}")
Ausgabe
Name | Fach | Note Anna | Mathe | 1 Ben | Englisch | 2

File I/O in Action: Highscore List

Imagine a game that saves the best scores. We use JSON for a highscore list that is loaded at startup and saved on exit.

Python
import json

# Highscore laden oder erstellen
try:
    with open("highscores.json", "r", encoding="utf-8") as f:
        scores = json.load(f)
except FileNotFoundError:
    scores = []

# Neuen Score hinzufügen
name = input("Dein Name: ")
punkte = int(input("Deine Punkte: "))
scores.append({"name": name, "punkte": punkte})

# Sortieren (absteigend)
scores.sort(key=lambda x: x["punkte"], reverse=True)

# Top 5 speichern
scores = scores[:5]
with open("highscores.json", "w", encoding="utf-8") as f:
    json.dump(scores, f, indent=2, ensure_ascii=False)

print("\n Highscores:")
for i, s in enumerate(scores, 1):
    print(f"  {i}. {s['name']}: {s['punkte']} Punkte")
Ausgabe
Dein Name: Max Deine Punkte: 1250 Highscores: 1. Max: 1250 Punkte

Warm-Up: Notebook with JSON

Create a program that saves notes as a JSON list and loads them. Use try/except in case the file does not exist yet.

Hinweis: import json try: with open('notizen.json', 'r') as f: notizen = json.load(f) except FileNotFoundError: notizen = [] text = input('Neue Notiz: ') notizen.append(text) with open('notizen.json', 'w') as f: json.dump(notizen, f, indent=2) print(f' {len(notizen)} Notiz(en) gespeichert.')

Solution
import json

try:
    with open('notizen.json', 'r') as f:
        notizen = json.load(f)
except FileNotFoundError:
    notizen = []

text = input('Neue Notiz: ')
notizen.append(text)

with open('notizen.json', 'w') as f:
    json.dump(notizen, f, indent=2)

print(f' {len(notizen)} Notiz(en) gespeichert.')

Challenge: Save/Load Todo List

Create a todo list that saves tasks with status (open/done) as JSON. Existing tasks are loaded at startup.

Hinweis: import json try: with open('todos.json', 'r') as f: todos = json.load(f) except FileNotFoundError: todos = [] while True: cmd = input('[add, list, save, exit] ').lower() if cmd == 'exit': break elif cmd == 'add': task = input('Aufgabe: ') todos.append({'task': task, 'done': False}) elif cmd == 'list': for i, t in enumerate(todos, 1): status = '' if t['done'] else '⬜' print(f' {i}. {status} {t["task"]}') elif cmd == 'save': with open('todos.json', 'w') as f: json.dump(todos, f, indent=2)

Solution
import json

try:
    with open('todos.json', 'r') as f:
        todos = json.load(f)
except FileNotFoundError:
    todos = []

while True:
    cmd = input('[add, list, save, exit] ').lower()
    if cmd == 'exit': break
    elif cmd == 'add':
        task = input('Aufgabe: ')
        todos.append({'task': task, 'done': False})
    elif cmd == 'list':
        for i, t in enumerate(todos, 1):
            status = '' if t['done'] else '⬜'
            print(f'  {i}. {status} {t["task"]}')
    elif cmd == 'save':
        with open('todos.json', 'w') as f:
            json.dump(todos, f, indent=2)

PyBuddy-Checkpoint: Save Configuration

PyBuddy saves its name, theme, and language in a config.json. The configuration is loaded at startup.

Hinweis: # pybuddy/main.py import json def lade_config(): try: with open('config.json', 'r') as f: return json.load(f) except FileNotFoundError: return {'name': 'PyBuddy', 'theme': 'dark', 'sprache': 'de'} def speichere_config(config): with open('config.json', 'w') as f: json.dump(config, f, indent=2) config = lade_config() print(f" {config['name']} startet...") print(f"🎨 Theme: {config['theme']}") config['name'] = input('Neuer Name: ') or config['name'] speichere_config(config) print('💾 Konfiguration gespeichert!')

Solution
# pybuddy/main.py
import json

def lade_config():
    try:
        with open('config.json', 'r') as f:
            return json.load(f)
    except FileNotFoundError:
        return {'name': 'PyBuddy', 'theme': 'dark', 'sprache': 'de'}

def speichere_config(config):
    with open('config.json', 'w') as f:
        json.dump(config, f, indent=2)

config = lade_config()
print(f" {config['name']} startet...")
print(f"🎨 Theme: {config['theme']}")
config['name'] = input('Neuer Name: ') or config['name']
speichere_config(config)
print('💾 Konfiguration gespeichert!')
Didactic Break

In The Legend of Zelda: Breath of the Wild the game saves your progress in a file — similar to JSON. Weapons, armor, map markers: Everything is serialized and loaded again on the next start. You are building the save system for your own game!

Zusammenfassung

  • with open() → process files safely
  • json.dump() / json.load() for structured data
  • try/except for robust code without crashes
  • csv module for table data
  • Files make data persistent between program starts