Anleitung

JSON in Python: Dateien lesen und schreiben, CSV, pathlib und UTF-8-Kodierung

Aktualisiert: · Skillaria.Top

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.

Die Arbeit mit JSON in Python braucht 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.

ModusWas 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.

FunktionWas 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

PythonJSON
dictObjekt {}
list, tupleArray []
strString
int, floatZahl
True / Falsetrue / false
Nonenull

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.

Häufige Fragen

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.

Das Thema im Video lernen

Dieses Thema wird im Kurs „Python 3.15: от новичка до профи“ ausführlich mit Praxis behandelt.

Zum Kurs