# Python JSON: Dateien lesen und schreiben, json.load, json.dumps, CSV und pathlib

URL: https://skillaria.top/de/guides/python/json-python

Für JSON in Python gibt es das eingebaute Modul json: json.load liest Daten aus einer geöffneten Datei, json.dump schreibt sie hinein, json.loads und json.dumps erledigen dasselbe mit Strings. Die Datei öffnen Sie mit with open(path, encoding="utf-8"), Pfade bauen Sie bequem mit pathlib.Path, und Tabellen lesen Sie mit dem Modul csv.

Für Python JSON brauchen Sie keine Fremdbibliotheken: Das Modul `json` gehört zur Standardbibliothek und verwandelt Dictionaries und Listen in Text und zurück. Daneben braucht man fast immer noch drei Dinge: die Funktion `open` mit `with`, das Modul `pathlib` für Pfade und das Modul `csv` für Tabellen. Im Folgenden alles der Reihe nach, mit funktionierendem Code und den Stolperfallen, über die man am häufigsten fällt.

## Die Funktion open in Python: Modi und Kodierung

Jede Textdatei öffnet man mit der eingebauten Funktion `open(path, mode, encoding=...)`. Sie liefert ein Dateiobjekt mit den Methoden `read`, `readline` und `write`, das Sie zeilenweise in einer Schleife durchlaufen können.

| Modus | Was er macht |
| --- | --- |

| `"r"` | Lesen (Standard). Fehlt die Datei, gibt es `FileNotFoundError` |

| `"w"` | Schreiben. Die Datei wird angelegt oder **schon beim Öffnen geleert** |

| `"a"` | Am Ende anhängen, der vorhandene Inhalt bleibt erhalten |

| `"x"` | Neue Datei anlegen; existiert sie schon, gibt es `FileExistsError` |

| `"b"` | Zusatz zum Modus: Arbeit mit Bytes (`"rb"`, `"wb"`) |

### Wozu with dient

Dateien muss man schließen. Sonst werden Daten unter Umständen nicht auf die Festplatte geschrieben, und das System hält den Dateideskriptor belegt. Die Konstruktion `with` schließt die Datei automatisch, auch wenn im Block ein Fehler auftritt.

```
with open("notes.txt", "w", encoding="utf-8") as f:
    f.write("Erste Zeile\n")
    f.write("Zweite Zeile\n")

with open("notes.txt", encoding="utf-8") as f:
    for line in f:
        print(line.rstrip("\n"))
```

Das zeilenweise Durchlaufen liest die Datei Zeile für Zeile und lädt sie nicht vollständig in den Speicher. So verarbeiten Sie sogar Logdateien mit mehreren Gigabyte. Die Methode `f.read()` liefert den ganzen Inhalt als einen String, `f.readlines()` eine Liste von Zeilen.

### Eine Zeile schreiben, ohne alten Inhalt zu löschen

Der häufigste Anfängerfehler ist, eine Datei mit dem Modus `"w"` zu öffnen, um eine Zeile „anzuhängen“. Der Modus `"w"` leert die Datei schon beim Öffnen, noch vor dem ersten `write`. Zum Anhängen nehmen Sie `"a"`, und um eine fremde Datei sicher nicht zu überschreiben, `"x"`.

```
with open("log.txt", "a", encoding="utf-8") as f:
    f.write("neuer Eintrag\n")
```

Beachten Sie, dass `write` keinen Zeilenumbruch hinzufügt. Das `"\n"` schreiben Sie ausdrücklich. Alternativ können Sie `print(..., file=f)` verwenden, das setzt den Umbruch für Sie.

## UTF-8-Kodierung: warum Zeichen kaputtgehen

Bis Python 3.15 verwendete `open()` ohne den Parameter `encoding` die Kodierung des Systems. Unter Linux und macOS ist das UTF-8, unter Windows mit deutschen Spracheinstellungen meist cp1252. Ein Skript, das auf dem Server funktionierte, zeigte auf dem Laptop eines Kollegen dann „Ã¤“ statt „ä“ oder brach mit `UnicodeDecodeError` ab.

In Python 3.15 ist der UTF-8-Modus nach PEP 686 standardmäßig aktiv: `open()` ohne `encoding` liest und schreibt UTF-8 auf allen Systemen. Das alte Verhalten erhalten Sie mit der Umgebungsvariablen `PYTHONUTF8=0` oder dem Schalter `-X utf8=0`. Die Systemkodierung fordern Sie ausdrücklich mit `encoding="locale"` an.

```
import sys
print(sys.flags.utf8_mode)   # 1 in Python 3.15

open("legacy.txt", encoding="locale")     # Systemkodierung
open("old_excel.csv", encoding="cp1252")  # Datei, die in cp1252 gespeichert wurde
```

Die Kehrseite: Eine alte CSV-Datei aus Excel oder einem Windows-Skript, die in cp1252 gespeichert ist, wird jetzt als UTF-8 gelesen und löst `UnicodeDecodeError` aus. Abhilfe: mit `encoding="cp1252"` lesen und als UTF-8 neu speichern. Die gute Praxis bleibt dieselbe: Geben Sie `encoding` immer ausdrücklich an, dann verhält sich der Code in jeder Version gleich.

## pathlib in Python: Pfade als Objekte

Pfade aus Strings zusammenzusetzen (`"data" + "/" + name`) ist mühsam und funktioniert nicht auf allen Systemen gleich. Das Modul `pathlib` bietet die Klasse `Path`, bei der Pfade mit dem Operator `/` verbunden werden und das Objekt aussagekräftige Eigenschaften hat.

```
from pathlib import Path

data = Path("data")
csv_path = data / "expenses.csv"

print(csv_path.name)    # expenses.csv
print(csv_path.stem)    # expenses
print(csv_path.suffix)  # .csv
print(csv_path.parent)  # data
print(csv_path.exists())

data.mkdir(parents=True, exist_ok=True)
(data / "hello.txt").write_text("Hallo", encoding="utf-8")
print((data / "hello.txt").read_text(encoding="utf-8"))

for p in data.glob("*.csv"):
    print(p)
```

Die Methoden `read_text` und `write_text` ersetzen bei kleinen Dateien die Kombination aus `open` und `with`. Ein `Path`-Objekt können Sie an `open`, `json` und `csv` übergeben, alle akzeptieren es. Einen Pfad relativ zum Skript statt zum aktuellen Ordner erhalten Sie mit `Path(__file__).parent / "data"`.

In Python 3.14 kamen die Methoden `copy()` und `move()` zu `Path` hinzu, für einfaches Kopieren braucht man also kein `shutil` mehr. In derselben Version wurde das Modul `compression.zstd` für die Kompression mit Zstandard in die Standardbibliothek aufgenommen (PEP 784).

## JSON in Python: load, dump, loads, dumps

JSON ist ein Textformat für den Datenaustausch: Es wird von APIs geliefert und dient zum Speichern von Konfigurationen und Berichten. Das Modul `json` kann zwei Dinge: Serialisierung (Python-Objekt wird zu JSON-Text) und Deserialisierung (Text wird zum Objekt). Es gibt vier Funktionen, und die Verwechslung zwischen ihnen ist eine häufige Frage.

| Funktion | Was sie macht |
| --- | --- |

| `json.dumps(obj)` | Objekt → JSON-String |

| `json.loads(s)` | JSON-String → Objekt |

| `json.dump(obj, f)` | Objekt → in eine geöffnete Datei schreiben |

| `json.load(f)` | JSON aus einer geöffneten Datei lesen |

Einfach zu merken: Das `s` am Ende steht für string und bedeutet die Arbeit mit Strings. Ohne `s` arbeiten Sie mit einer Datei.

### Zuordnung der Typen

| Python | JSON |
| --- | --- |

| `dict` | Objekt `{}` |

| `list`, `tuple` | Array `[]` |

| `str` | String |

| `int`, `float` | Zahl |

| `True` / `False` | `true` / `false` |

| `None` | `null` |

Ein Tupel wird beim Zurücklesen zu einer Liste. Mengen, Datumswerte und `Decimal` kennt das Modul nicht und wirft `TypeError: Object of type ... is not JSON serializable`.

### JSON in eine Datei speichern

```
import json
from pathlib import Path

report = {
    "month": "2026-10",
    "total": 15230.5,
    "categories": {"Essen": 8200, "Verkehr": 2100},
    "tags": ["Zuhause", "Arbeit"],
}

path = Path("data/report.json")
path.parent.mkdir(parents=True, exist_ok=True)
with path.open("w", encoding="utf-8") as f:
    json.dump(report, f, ensure_ascii=False, indent=2)
```

Der Parameter `ensure_ascii=False` speichert Umlaute unverändert. Ohne ihn stünde im Dateiinhalt statt „Essen“ eine Escape-Folge wie `ä`. Das wäre gültiges JSON, aber für Menschen schwer lesbar. `indent=2` sorgt für eine übersichtliche Formatierung mit Einrückung.

### JSON aus einer Datei lesen

```
with open("data/report.json", encoding="utf-8") as f:
    data = json.load(f)

print(data["total"])               # 15230.5
print(data["categories"]["Essen"]) # 8200
```

Das Ergebnis ist ein gewöhnliches Dictionary oder eine Liste, mit denen Sie wie gewohnt arbeiten. Ist die Datei kein gültiges oder ein abgeschnittenes JSON, wird `json.JSONDecodeError` mit Zeilen- und Positionsangabe ausgelöst. Diese Ausnahme sollten Sie abfangen, wenn die Daten von außen kommen.

### JSON-String parsen und schön ausgeben

```
import json

raw = '{"name": "Anna", "skills": ["python", "sql"], "active": true}'
user = json.loads(raw)
print(user["skills"][0])   # python

print(json.dumps(user, ensure_ascii=False, indent=2, sort_keys=True))
```

`sort_keys=True` sortiert die Schlüssel bei der Ausgabe, das ist praktisch, um Dateien in git zu vergleichen. Zum schnellen Formatieren einer Datei im Terminal gibt es ein eingebautes Hilfsprogramm: `python -m json.tool data/report.json`.

Die Antwort einer HTTP-API ist ebenfalls ein JSON-String. Die Bibliothek `requests` wertet ihn mit `response.json()` aus, intern passiert dabei dasselbe wie bei `json.loads`.

### Falle: JSON-Schlüssel sind immer Strings

```
d = {1: "Januar", 2: "Februar"}
back = json.loads(json.dumps(d))
print(back == d)   # False
print(back)        # {'1': 'Januar', '2': 'Februar'}
# back[1] -> KeyError, richtig ist back["1"]

fixed = {int(k): v for k, v in back.items()}
```

In JSON können Objektschlüssel nur Strings sein. Numerische Schlüssel werden deshalb nach dem Hin- und Rückweg zu Strings. Wandeln Sie sie beim Lesen wieder um.

### Eigene Typen: Datumswerte und Decimal

```
import json
from datetime import date

def default(obj):
    if isinstance(obj, date):
        return obj.isoformat()
    raise TypeError(f"Kann {type(obj).__name__} nicht serialisieren")

print(json.dumps({"day": date(2026, 10, 1)}, default=default))
# {"day": "2026-10-01"}
```

Die Funktion im Parameter `default` wird für jedes unbekannte Objekt aufgerufen. In komplizierteren Fällen können Sie von `json.JSONEncoder` erben und die Methode `default` überschreiben.

### Ein Element an ein JSON-Array anhängen

Ein JSON-Array lässt sich nicht wie ein Textlog am Ende erweitern: Die Datei muss vollständig gelesen, geändert und wieder geschrieben werden.

```
path = Path("data/items.json")
items = json.loads(path.read_text(encoding="utf-8")) if path.exists() else []
items.append({"id": len(items) + 1, "title": "neu"})
path.write_text(json.dumps(items, ensure_ascii=False, indent=2), encoding="utf-8")
```

Bei vielen Einträgen, die ständig hinzukommen, ist das Format JSON Lines praktischer: ein JSON-Objekt pro Zeile, die Datei wird im Modus `"a"` geöffnet.

## CSV in Python: das Modul csv

CSV ist eine Tabelle in einer Textdatei: Zeilen sind Datensätze, Werte sind durch Kommas getrennt. Das Modul `csv` behandelt Anführungszeichen, Kommas innerhalb von Werten und Zeilenumbrüche korrekt, was ein handgeschriebenes `split(",")` nicht leistet.

```
import csv

with open("data/expenses.csv", newline="", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    total = 0.0
    for row in reader:
        total += float(row["amount"])
        print(row["date"], row["category"], row["amount"])
print("Gesamt:", total)
```

`csv.DictReader` macht aus jeder Zeile ein Dictionary, die Schlüssel stammen aus der Kopfzeile. Alle Werte sind Strings: Zahlen und Datumswerte wandeln Sie selbst um (`float`, `int`, `date.fromisoformat`). Eine Datei mit Semikolon als Trennzeichen (so speichert deutsches Excel häufig) lesen Sie mit `delimiter=";"`.

```
rows = [
    {"date": "2026-10-01", "category": "Essen", "amount": 450},
    {"date": "2026-10-02", "category": "Verkehr", "amount": 60},
]
with open("data/out.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["date", "category", "amount"])
    writer.writeheader()
    writer.writerows(rows)
```

Beim Schreiben ist `newline=""` zwingend: Ohne den Parameter entstehen unter Windows Leerzeilen zwischen den Datensätzen. Wenn die Datei in Excel geöffnet werden soll, verwenden Sie `encoding="utf-8-sig"`. Die BOM-Markierung hilft Excel, UTF-8 zu erkennen.

## Von CSV zu JSON: ein vollständiges Beispiel

```
import csv
import json
from collections import defaultdict
from pathlib import Path

src = Path("data/expenses.csv")
dst = Path("data/report.json")

by_category = defaultdict(float)
with src.open(newline="", encoding="utf-8") as f:
    for row in csv.DictReader(f):
        by_category[row["category"]] += float(row["amount"])

report = {"total": sum(by_category.values()), "categories": dict(by_category)}
dst.write_text(json.dumps(report, ensure_ascii=False, indent=2), encoding="utf-8")
print(dst.read_text(encoding="utf-8"))
```

Das ist der Kern jedes Berichtsskripts: Eingabe aus CSV, Zusammenfassung in einem Dictionary, Ausgabe als JSON.

## Typische Fehler

- `FileNotFoundError` — der Pfad ist relativ und bezieht sich auf den Ordner, aus dem Sie starten, nicht auf das Skript. Verwenden Sie `Path(__file__).parent`.
- Die Datei ist leer, obwohl Sie etwas angehängt haben — Sie haben mit `"w"` statt `"a"` geöffnet.
- `UnicodeDecodeError` — die Datei hat eine andere Kodierung; geben Sie sie ausdrücklich an (`cp1252`, `utf-8-sig`).
- `TypeError: Object of type set is not JSON serializable` — wandeln Sie in eine Liste um oder übergeben Sie `default`.
- `KeyError` nach dem Laden von JSON — numerische Schlüssel sind zu Strings geworden.
- Die eigene Datei heißt `json.py` oder `csv.py` — sie verdeckt das Standardmodul, und `import json` lädt Ihre Datei.

## Fazit

Für JSON in Python genügt die Standardbibliothek: `json.load` und `json.dump` für Dateien, `loads` und `dumps` für Strings, `ensure_ascii=False` und `indent` für eine lesbare Ausgabe. Öffnen Sie Dateien mit `with` und einer ausdrücklichen Kodierung, bauen Sie Pfade mit `pathlib`, und lesen Sie Tabellen mit `csv.DictReader`. Im Python-Kurs wird das Thema praktisch behandelt: Der Ausgabentracker liest Ausgaben aus einer CSV-Datei und speichert den Bericht als JSON.

## FAQ

**Worin unterscheidet sich json.load von json.loads?**

json.load liest JSON aus einem geöffneten Dateiobjekt, json.loads verarbeitet einen String. Ebenso schreibt json.dump in eine Datei, json.dumps liefert einen String zurück.

**Wie speichere ich Umlaute in JSON, ohne \u-Folgen zu erhalten?**

Übergeben Sie ensure_ascii=False an json.dump oder json.dumps und öffnen Sie die Datei mit encoding="utf-8".

**Muss ich eine Bibliothek für JSON in Python installieren?**

Nein, das Modul json gehört zur Standardbibliothek. Es genügt import json.

**Kann ich Datumswerte oder Mengen direkt in JSON speichern?**

Nicht direkt. Sie müssen sie umwandeln, etwa ein Datum mit isoformat in einen ISO-String und eine Menge in eine Liste, oder eine Funktion an den Parameter default übergeben.

**Wie lese ich ein großes JSON, das nicht in den Speicher passt?**

Das Standardmodul json.load liest die Datei vollständig. Bei großen Datenmengen speichern Sie die Daten im Format JSON Lines und verarbeiten sie Zeile für Zeile mit json.loads.


---
Source: Skillaria.Top (https://skillaria.top)
