W3docs

Python CSV-Dateien

CSV-Dateien in Python lesen und schreiben mit dem integrierten csv-Modul, einschließlich csv.reader, csv.writer, DictReader und DictWriter mit Praxisbeispielen.

CSV (Comma-Separated Values) ist eines der verbreitetsten Formate zum Austausch von Tabellendaten — jede Tabellenkalkulationsanwendung, jede Datenbank und jedes Data-Science-Tool kann es lesen und schreiben. Das integrierte Python-csv-Modul übernimmt die kniffligen Details automatisch: Es setzt Felder in Anführungszeichen, die Kommas enthalten, gleicht Zeilenumbruch-Eigenheiten verschiedener Betriebssysteme aus und ordnet Zeilen Dictionaries zu. Es muss nichts installiert werden; csv ist in jeder Python-Installation enthalten.

Dieses Kapitel behandelt das Lesen und Schreiben von CSV-Dateien, die Arbeit mit DictReader und DictWriter, den Umgang mit benutzerdefinierten Trennzeichen sowie häufige Fallstricke, die es zu vermeiden gilt.

Was ist eine CSV-Datei?

Eine CSV-Datei ist eine Klartextdatei, in der jede Zeile eine Datenzeile darstellt und die einzelnen Felder durch ein Trennzeichen — in der Regel ein Komma — voneinander getrennt sind. Hier ist ein minimales Beispiel:

name,age,city
Alice,30,New York
Bob,25,London

Die erste Zeile ist typischerweise ein Header, der die einzelnen Spalten benennt. Die nachfolgenden Zeilen enthalten die eigentlichen Daten. Wenn ein Feldwert selbst ein Komma enthält, wird das Feld in doppelte Anführungszeichen eingeschlossen:

name,bio
Alice,"Engineer, New York"

Das csv-Modul verarbeitet diese Anführungszeichenlogik transparent, sodass keine manuelle Verarbeitung erforderlich ist.

CSV-Dateien lesen mit csv.reader

csv.reader verwandelt eine geöffnete Datei (oder einen beliebigen iterierbaren Ausdruck aus Strings) in einen Iterator, der jede Zeile als Python-Liste zurückgibt.

Grundmuster — eine CSV-Datei zeilenweise lesen

import csv

with open("people.csv", newline="") as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)

Das Argument newline="" ist wichtig. Ohne es kann Pythons universelle Zeilenumbruchübersetzung unter Windows zusätzliche Leerzeilen einfügen, weil das csv-Modul die Zeilenumbrüche intern selbst verarbeitet.

Wenn people.csv die obigen Beispieldaten enthält, lautet die Ausgabe:

['name', 'age', 'city']
['Alice', '30', 'New York']
['Bob', '25', 'London']

Beachten Sie, dass alle Werte — einschließlich der Zahl 30 — als Strings zurückgegeben werden. Das csv-Modul leitet keine Datentypen ab; konvertieren Sie die Werte bei Bedarf selbst.

Die Kopfzeile überspringen

Wenn nur die Datenzeilen und nicht die Kopfzeile benötigt werden, rufen Sie einmal next() auf dem Reader auf, um die erste Zeile zu verbrauchen:

Kopfzeile mit next() überspringen

import csv

with open("people.csv", newline="") as f:
    reader = csv.reader(f)
    header = next(reader)          # consume and store the header
    print("Columns:", header)
    for row in reader:             # only data rows remain
        name, age, city = row
        print(f"{name} is {age} years old and lives in {city}.")

Ausgabe:

Columns: ['name', 'age', 'city']
Alice is 30 years old and lives in New York.
Bob is 25 years old and lives in London.

Alle Zeilen in eine Liste laden

Wenn die gesamte Datei auf einmal im Speicher benötigt wird, übergeben Sie den Reader an list():

import csv

with open("people.csv", newline="") as f:
    reader = csv.reader(f)
    rows = list(reader)

print(rows[0])   # header row
print(rows[1])   # first data row

Ausgabe:

['name', 'age', 'city']
['Alice', '30', 'New York']

CSV-Dateien schreiben mit csv.writer

csv.writer schreibt Zeilen in ein beliebiges dateiähnliches Objekt und setzt dabei automatisch Felder in Anführungszeichen, die das Trennzeichen, doppelte Anführungszeichen oder Zeilenumbrüche enthalten.

Zeilen in eine neue CSV-Datei schreiben

import csv

rows = [
    ["product", "price", "quantity"],
    ["Apple", 1.2, 50],
    ["Banana", 0.5, 100],
    ["Cherry", 3.0, 30],
]

with open("inventory.csv", "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerows(rows)

Nach der Ausführung enthält inventory.csv:

product,price,quantity
Apple,1.2,50
Banana,0.5,100
Cherry,3.0,30

Verwenden Sie writer.writerow(row), um eine einzelne Zeile zu schreiben, oder writer.writerows(rows), um mehrere auf einmal zu schreiben. Beide akzeptieren beliebige Iterables.

Warum newline="" beim Schreiben wichtig ist

Unter Windows öffnet Python Textdateien in einem Modus, der \n in \r\n übersetzt. Das csv-Modul schreibt standardmäßig ebenfalls \r\n-Zeilenenden. Zusammen ergibt das \r\r\n — eine Leerzeile zwischen jeder Zeile, wenn die Datei in einem anderen Programm geöffnet wird. Die Angabe von newline="" unterdrückt die zusätzliche Übersetzung und lässt csv die Zeilenenden selbst verwalten.

CSV-Dateien lesen mit csv.DictReader

DictReader ordnet jede Zeile einem OrderedDict (oder einem einfachen dict in Python 3.8+) zu, das nach den Spaltennamen in der Kopfzeile geordnet ist. Dies ist der bevorzugte Ansatz, wenn Spalten aussagekräftige Namen haben und man auf diese per Name statt per Index zugreifen möchte.

Eine CSV-Datei als Folge von Dictionaries lesen

import csv

with open("people.csv", newline="") as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row["name"], "—", row["city"])

Ausgabe:

Alice — New York
Bob — London

DictReader liest die erste Zeile automatisch als Header. Dies kann durch die Übergabe eines fieldnames-Arguments überschrieben werden:

import csv

# File has no header; provide field names explicitly
with open("data_no_header.csv", newline="") as f:
    reader = csv.DictReader(f, fieldnames=["name", "age", "city"])
    for row in reader:
        print(row)

Das Attribut reader.fieldnames enthält stets die Liste der verwendeten Spaltennamen, was bei der Untersuchung vor der Zeilenverarbeitung nützlich ist.

CSV-Dateien schreiben mit csv.DictWriter

DictWriter ist das Gegenstück zu DictReader. Die Spaltennamen werden vorab angegeben, dann werden Dictionaries geschrieben — der Writer ordnet jeden Schlüssel der richtigen Spalte zu.

Eine Liste von Dictionaries in eine CSV-Datei schreiben

import csv

people = [
    {"name": "Alice", "age": 30, "city": "New York"},
    {"name": "Bob", "age": 25, "city": "London"},
]

fieldnames = ["name", "age", "city"]

with open("people_out.csv", "w", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    writer.writeheader()          # writes the column-name row
    writer.writerows(people)

Die resultierende Datei:

name,age,city
Alice,30,New York
Bob,25,London

writeheader() verwendet die beim Erstellen übergebene fieldnames-Liste. Der Aufruf erfolgt einmalig vor allen writerow()-Aufrufen.

Umgang mit zusätzlichen oder fehlenden Schlüsseln

Standardmäßig wirft DictWriter einen ValueError, wenn ein Dictionary einen Schlüssel enthält, der nicht in fieldnames enthalten ist. Dieses Verhalten lässt sich mit dem Parameter extrasaction ändern:

writer = csv.DictWriter(f, fieldnames=fieldnames, extrasaction="ignore")

Umgekehrt schreibt der Writer einen leeren String für ein fehlendes Feld, es sei denn, ein restval-Standardwert wird angegeben:

writer = csv.DictWriter(f, fieldnames=fieldnames, restval="N/A")

Benutzerdefinierte Trennzeichen und Anführungszeichen

CSV-Dateien in der Praxis sind nicht immer durch Kommas getrennt. Tabulatorgetrennte Werte (TSV) und durch Pipe-Zeichen getrennte Dateien sind verbreitet. Verwenden Sie den Parameter delimiter, um damit umzugehen:

Eine tabulatorgetrennte Datei lesen

import csv

with open("scores.tsv", newline="") as f:
    reader = csv.reader(f, delimiter="\t")
    for row in reader:
        print(row)

Eine durch Pipe-Zeichen getrennte Datei schreiben

import csv

with open("output.psv", "w", newline="") as f:
    writer = csv.writer(f, delimiter="|")
    writer.writerow(["id", "name", "score"])
    writer.writerow([1, "Alice", 98])
    writer.writerow([2, "Bob", 87])

Ausgabedatei:

id|name|score
1|Alice|98
2|Bob|87

Anführungszeichen-Konstanten

Der Parameter quoting steuert, welche Felder in der Ausgabe in Anführungszeichen gesetzt werden:

KonstanteWertVerhalten
csv.QUOTE_MINIMAL0Nur Felder in Anführungszeichen setzen, die das Trennzeichen, das Anführungszeichen selbst oder einen Zeilenumbruch enthalten (Standard)
csv.QUOTE_ALL1Jedes Feld in Anführungszeichen setzen
csv.QUOTE_NONNUMERIC2Alle nicht-numerischen Felder in Anführungszeichen setzen; der Reader konvertiert felder ohne Anführungszeichen zu float
csv.QUOTE_NONE3Niemals Anführungszeichen setzen; Fehler auslösen, wenn das Trennzeichen in einem Feld vorkommt

Jedes Feld in Anführungszeichen setzen erzwingen

import csv, io

output = io.StringIO()
writer = csv.writer(output, quoting=csv.QUOTE_ALL)
writer.writerow(["name", "bio"])
writer.writerow(["Alice", "Engineer, New York"])
print(output.getvalue())

Ausgabe:

"name","bio"
"Alice","Engineer, New York"

io.StringIO für CSV im Arbeitsspeicher verwenden

Wenn kein Zugriff auf das Dateisystem nötig ist — etwa in Tests oder bei der Verarbeitung von CSV-Daten aus einer API — kann io.StringIO als dateiähnliches Objekt verwendet werden:

CSV aus einem String verarbeiten

import csv
import io

raw = "name,score\nAlice,95\nBob,87\n"

reader = csv.DictReader(io.StringIO(raw))
for row in reader:
    print(row["name"], "scored", row["score"])

Ausgabe:

Alice scored 95
Bob scored 87

Häufige Fallstricke

Alle Werte sind Strings

csv.reader und DictReader geben stets Strings zurück. Werte müssen explizit konvertiert werden:

age = int(row["age"])
price = float(row["price"])

Kodierungsprobleme

Dateien müssen mit der richtigen Kodierung geöffnet werden, um UnicodeDecodeError zu vermeiden. UTF-8 ist die häufigste Kodierung für moderne CSV-Dateien, aber aus Excel exportierte Dateien verwenden möglicherweise latin-1 oder cp1252:

with open("data.csv", newline="", encoding="utf-8") as f:
    reader = csv.reader(f)

Leerzeilen

Wenn eine CSV-Datei Leerzeilen zwischen Datenzeilen enthält, gibt csv.reader dafür leere Listen [] zurück. Diese lassen sich herausfiltern:

import csv

with open("data.csv", newline="") as f:
    reader = csv.reader(f)
    for row in reader:
        if not row:        # skip blank lines
            continue
        print(row)

Fehlerbehandlung

Dateioperationen sollten in einem try/except-Block gekapselt werden, um fehlende Dateien und Berechtigungsfehler sauber abzufangen:

import csv

try:
    with open("data.csv", newline="") as f:
        reader = csv.reader(f)
        for row in reader:
            print(row)
except FileNotFoundError:
    print("Error: data.csv was not found.")
except PermissionError:
    print("Error: no permission to read data.csv.")

csv vs. Pandas für große Dateien

Das csv-Modul ist ideal für:

  • Kleine bis mittlere Dateien (bis zu einigen hundert MB)
  • Skripte, bei denen Pandas nicht installiert ist
  • Situationen, in denen eine feinkörnige Kontrolle über das Lesen und Schreiben benötigt wird

Für große Datensätze, komplexes Filtern oder Aggregationsoperationen bietet die Drittanbieter-Bibliothek pandas die Funktionen pd.read_csv() und DataFrame.to_csv(), die deutlich schneller und funktionsreicher sind.

Alles zusammen

Das folgende Beispiel liest eine CSV-Datei, filtert Zeilen anhand einer Bedingung und schreibt die gefilterten Ergebnisse in eine neue Datei:

Zeilen filtern und eine neue CSV-Datei schreiben

import csv

input_file = "inventory.csv"
output_file = "expensive.csv"

with open(input_file, newline="") as infile, \
     open(output_file, "w", newline="") as outfile:

    reader = csv.DictReader(infile)
    writer = csv.DictWriter(outfile, fieldnames=reader.fieldnames)

    writer.writeheader()
    for row in reader:
        if float(row["price"]) >= 1.0:
            writer.writerow(row)

print(f"Filtered rows written to {output_file}.")

Dieses Muster — beide Dateien im selben with-Block öffnen, Zeilen vom Reader zum Writer streamen — verarbeitet Dateien beliebiger Größe, ohne alles auf einmal in den Speicher zu laden.

Verwandte Kapitel

Übungen

Übung
Which csv module class maps each CSV row to a dictionary keyed by column names?
Which csv module class maps each CSV row to a dictionary keyed by column names?
Was this page helpful?