CSV-Dateien¶
CSV ist eine einfache Tabelle als Textdatei: eine Zeile pro Datensatz, die Werte durch Komma oder Semikolon getrennt. Excel und fast jedes andere Programm kann CSV lesen und schreiben — deshalb ist es das Standardformat für Import und Export.
Ausführliches dazu: CSV schreiben & einlesen.
Die Beispiele speichern Dateien im Übungsordner /beispiele/csv der
Datei-Sandbox; das letzte Beispiel räumt ihn wieder auf.
Einsteiger¶
1. Einen CSV-Text lesen¶
csv.parse zerlegt einen Text in Zeilen und Werte. Heraus kommt eine Liste
von Zeilen, jede Zeile ist eine Liste von Werten.
var zeilen = csv.parse("Schmitz,Köln\nWeber,Berlin");
log.info(zeilen.length + " Zeilen");
log.info("Zeile 1, Wert 2: " + zeilen[0][1]); // Köln
Die Zählung beginnt bei 0: zeilen[0] ist die erste Zeile.
2. Die Kopfzeile nutzen¶
Mit header: true wird die erste Zeile zu Spaltennamen. Jede Zeile ist dann
ein Objekt — viel lesbarer.
var text = "Name,Ort\nSchmitz,Köln\nWeber,Berlin";
var leute = csv.parse(text, { header: true });
leute.forEach(function (p) {
log.info(p.Name + " wohnt in " + p.Ort);
});
3. Semikolon als Trennzeichen¶
Deutsche Excel-Dateien trennen mit ;. Das stellst du mit separator ein.
var text = "Name;Umsatz\nSchmitz;12500,00";
var zeilen = csv.parse(text, { header: true, separator: ";" });
log.info(zeilen[0].Name + ": " + zeilen[0].Umsatz);
4. Eine CSV erzeugen¶
Der StandardPrinter baut eine CSV Zeile für Zeile. println([...]) schreibt
eine Zeile.
var p = new csv.StandardPrinter({ lineSeparator: "UNIX" });
p.println(["Nr", "Artikel", "Preis"]);
p.println([1, "Bleistift", 0.80]);
p.println([2, "Radiergummi", 1.20]);
log.info(p.toString());
5. Die CSV als Datei speichern¶
Eine Zuweisung an einen Dateipfad genügt.
var p = new csv.StandardPrinter({ separator: ";" });
p.println(["Name", "Ort", "Umsatz"]);
p.println(["Bäckerei Schmitz", "Köln", "12500,00"]);
p.println(["Autohaus Weber", "Berlin", "98000,50"]);
p.println(["Blumen Meyer", "Köln", "3400,00"]);
fs["/beispiele/csv/kunden.csv"] = p;
log.info("Datei gespeichert: " + fs["/beispiele/csv/kunden.csv"].size + " Byte");
6. Eine CSV-Datei einlesen¶
csv.parse nimmt statt eines Textes auch direkt eine Datei.
var kunden = csv.parse(fs["/beispiele/csv/kunden.csv"], { header: true, separator: ";" });
log.info(kunden.length + " Kunden gelesen");
log.info("Erster: " + kunden[0].Name);
7. Zahlen aus einer CSV addieren¶
Werte aus einer CSV sind immer Text. kc.num versteht auch 12500,00 und
1.234,56.
var kunden = csv.parse(fs["/beispiele/csv/kunden.csv"], { header: true, separator: ";" });
var summe = 0;
kunden.forEach(function (k) { summe += kc.num(k.Umsatz); });
log.info("Summe: " + summe.toFixed(2)); // 113900.50
8. Nur bestimmte Zeilen verwenden¶
filter behält nur die Zeilen, für die die Bedingung stimmt.
var kunden = csv.parse(fs["/beispiele/csv/kunden.csv"], { header: true, separator: ";" });
var koeln = kunden.filter(function (k) { return k.Ort === "Köln"; });
log.info(koeln.length + " Kunden in Köln");
Fortgeschritten¶
9. Leerzeichen um die Werte entfernen¶
Manche Programme schreiben "Köln " mit Leerzeichen. trim: true räumt
das beim Lesen auf.
var zeilen = csv.parse("Name , Ort\n Schmitz , Köln ", { header: true, trim: true });
log.info("[" + zeilen[0].Ort + "]"); // [Köln]
10. Vorspann-Zeilen überspringen¶
Exporte haben oft ein paar Zeilen Beschreibung vor der eigentlichen Tabelle.
skip überspringt sie.
var text = "Export vom 01.03.2026\nSystem: Warenwirtschaft\nName;Ort\nSchmitz;Köln";
var zeilen = csv.parse(text, { header: true, separator: ";", skip: 2 });
log.info(zeilen[0].Name + " / " + zeilen[0].Ort);
11. Sonderzeichen in Werten¶
Enthält ein Wert das Trennzeichen, Anführungszeichen oder einen Zeilenumbruch, setzt der Printer ihn automatisch in Anführungszeichen — und der Parser liest ihn wieder richtig.
var p = new csv.StandardPrinter({ separator: ";", lineSeparator: "UNIX" });
p.println(["Firma", "Hinweis"]);
p.println(["Müller; Söhne", 'Sagt "Hallo"']);
log.info(p.toString()); // "Müller; Söhne";"Sagt ""Hallo"""
var zurueck = csv.parse(p.toString(), { header: true, separator: ";" });
log.info("zurückgelesen: " + zurueck[0].Firma + " | " + zurueck[0].Hinweis);
12. Zeile für Zeile lesen¶
Für sehr große Dateien liest der StandardParser eine Zeile nach der
anderen. line ist die Nummer der aktuellen Zeile.
var parser = new csv.StandardParser(fs["/beispiele/csv/kunden.csv"], { separator: ";" });
var kopf = parser.nextLine(); // erste Zeile = Spaltennamen
var zeile;
while ((zeile = parser.nextLine()) !== null) {
log.info("Zeile " + parser.line + ": " + zeile[0]);
}
parser.close();
nextLine() liefert null, wenn die Datei zu Ende ist.
13. Eine CSV, die Excel richtig öffnet¶
Deutsches Excel erwartet Semikolon, Windows-Zeilenenden und ein BOM (ein unsichtbares Zeichen am Anfang), damit Umlaute stimmen.
var p = new csv.StandardPrinter({ separator: ";", lineSeparator: "WINDOWS", bom: true });
p.println(["Straße", "Größe"]);
p.println(["Hauptstraße 1", "groß"]);
fs["/beispiele/csv/excel.csv"] = p;
var bytes = fs["/beispiele/csv/excel.csv"].readBytes();
log.info("BOM: " + (bytes[0] === -17 ? "ja" : "nein")); // 0xEF als Byte = -17
14. An eine vorhandene Datei anhängen¶
appendTo schreibt ans Ende, statt die Datei zu überschreiben — praktisch
für ein Protokoll.
var protokoll = fs["/beispiele/csv/protokoll.csv"];
if (!protokoll.exists) {
var kopf = new csv.StandardPrinter({ separator: ";" });
kopf.println(["Zeitpunkt", "Benutzer", "Aktion"]);
kopf.writeTo(protokoll);
}
var p = new csv.StandardPrinter({ separator: ";" });
p.println([new Date().format("dd.MM.yyyy HH:mm"), ctx.user.name, "Beispiel ausgeführt"]);
p.appendTo(protokoll);
log.info(csv.parse(protokoll, { separator: ";" }).length + " Zeilen im Protokoll");
15. Einen anderen Zeichensatz verwenden¶
Ältere Programme erwarten ISO-8859-1 statt UTF-8. Beim Schreiben und
Lesen gibst du ihn mit an.
var p = new csv.StandardPrinter({ separator: ";", encoding: "ISO-8859-1" });
p.println(["Größe", "Übergröße"]);
fs["/beispiele/csv/alt.csv"] = p;
var zeilen = csv.parse(fs["/beispiele/csv/alt.csv"], { separator: ";", encoding: "ISO-8859-1" });
log.info(zeilen[0][0]); // Größe – richtig gelesen
Liest du so eine Datei ohne encoding, erscheinen statt Umlauten
Fragezeichen.
16. Datenbank-Abfrage als CSV¶
Eine SQL-Abfrage direkt in eine Datei schreiben.
var p = new csv.StandardPrinter({ separator: ";", bom: true });
p.println(["Login", "Vorname", "Nachname", "E-Mail"]);
var n = 0;
db.forEach("SELECT LOGIN_NAME, FIRST_NAME, LAST_NAME, EMAIL FROM USERS ORDER BY LOGIN_NAME", function (u) {
p.println([u.login_name, u.first_name, u.last_name, u.email]);
n++;
});
fs["/beispiele/csv/benutzer.csv"] = p;
log.info(n + " Benutzer exportiert");
17. Eine CSV in eine Detail-Tabelle übernehmen¶
Jede CSV-Zeile wird zu einer Tabellenzeile im Formular.
var kunden = csv.parse(fs["/beispiele/csv/kunden.csv"], { header: true, separator: ";" });
ctx.form.positionen = kunden.map(function (k) {
return { name: k.Name, ort: k.Ort, umsatz: kc.num(k.Umsatz) };
});
log.info(ctx.form.positionen.length + " Zeilen in die Tabelle übernommen");
Die Namen links (name, ort, umsatz) müssen die Spaltennamen deiner
Detail-Tabelle sein.
18. Nur bestimmte Spalten übernehmen¶
Aus einer breiten CSV nur zwei Spalten in einer neuen Reihenfolge ausgeben.
var kunden = csv.parse(fs["/beispiele/csv/kunden.csv"], { header: true, separator: ";" });
var p = new csv.StandardPrinter({ separator: ";", lineSeparator: "UNIX" });
p.println(["Ort", "Name"]);
kunden.forEach(function (k) { p.println([k.Ort, k.Name]); });
log.info(p.toString());
Profi¶
19. Import mit Prüfung¶
Fehlerhafte Zeilen werden nicht übernommen, sondern mit Zeilennummer gesammelt. So weiß die Fachabteilung genau, was sie korrigieren muss.
var text = "Nr;Name;Menge\n1;Stift;10\n2;;5\n3;Block;viele\n4;Mappe;2";
var zeilen = csv.parse(text, { header: true, separator: ";", trim: true });
var gueltig = [], fehler = [];
// Indizierte Schleife, nicht forEach: auf dem Ergebnis von csv.parse ist
// forEach Javas Fassung und reicht KEINEN Index durch (siehe Hinweis unten).
for (var i = 0; i < zeilen.length; i++) {
var z = zeilen[i];
var zeilennr = i + 2; // +1 wegen Kopfzeile, +1 weil Menschen ab 1 zählen
if (!z.Name) {
fehler.push("Zeile " + zeilennr + ": Name fehlt");
} else if (!/^\d+$/.test(z.Menge)) {
fehler.push("Zeile " + zeilennr + ": Menge '" + z.Menge + "' ist keine Zahl");
} else {
gueltig.push({ nr: z.Nr, name: z.Name, menge: Number(z.Menge) });
}
}
log.info(gueltig.length + " gültig, " + fehler.length + " fehlerhaft");
fehler.forEach(function (f) { log.warn(f); });
20. CSV in die Datenbank importieren¶
Erst prüfen, dann in einem Rutsch mit db.batch einfügen. Die
Übungstabelle wird am Ende wieder entfernt.
db.update("CREATE TABLE IF NOT EXISTS bsp_import (name VARCHAR(100), ort VARCHAR(60), umsatz DECIMAL(12,2))");
var kunden = csv.parse(fs["/beispiele/csv/kunden.csv"], { header: true, separator: ";" });
var zeilen = kunden.map(function (k) {
return { name: k.Name, ort: k.Ort, umsatz: kc.num(k.Umsatz) };
});
db.batch("INSERT INTO bsp_import (name, ort, umsatz) VALUES (${name}, ${ort}, ${umsatz})", zeilen);
log.info("importiert: " + db.scalar("SELECT COUNT(*) FROM bsp_import"));
db.update("DROP TABLE bsp_import"); // Übung aufräumen
21. Die CSV zum Herunterladen anbieten¶
delivery.deliver macht aus den Bytes einen Download-Link, view.Link
zeigt ihn im Formular.
var p = new csv.StandardPrinter({ separator: ";", bom: true });
p.println(["Datum", "Wert"]);
p.println([new Date().format("dd.MM.yyyy"), 42]);
var url = delivery.deliver(p.toByteArray(), { name: "auswertung.csv", mime: "text/csv" });
view.add(new view.Link(url, "Auswertung als CSV herunterladen"));
log.info("Link erzeugt: " + url);
22. Gruppensummen berechnen und als Bericht schreiben¶
Umsätze je Ort addieren und sortiert als neue CSV ausgeben.
var kunden = csv.parse(fs["/beispiele/csv/kunden.csv"], { header: true, separator: ";" });
var jeOrt = {};
kunden.forEach(function (k) {
jeOrt[k.Ort] = (jeOrt[k.Ort] || 0) + kc.num(k.Umsatz);
});
var p = new csv.StandardPrinter({ separator: ";", lineSeparator: "UNIX" });
p.println(["Ort", "Umsatz"]);
Object.keys(jeOrt).sort().forEach(function (ort) {
p.println([ort, jeOrt[ort].toFixed(2).replace(".", ",")]); // deutsches Komma
});
fs["/beispiele/csv/umsatz-je-ort.csv"] = p;
log.info(p.toString());
23. Einen alten Excel-Export lesen¶
Der ExcelParser aus dem Modul CSVService liest standardmäßig
ISO-8859-1 — so wie ältere Excel-Versionen speichern.
var m = modules.use("CSVService");
var parser = new m.ExcelParser(fs["/beispiele/csv/alt.csv"], { separator: ";" });
var zeile;
while ((zeile = parser.nextLine()) !== null) {
log.info(zeile.join(" | "));
}
24. Zwei Listen abgleichen¶
Welche Einträge sind neu dazugekommen, welche fehlen jetzt? Ein Objekt als „Nachschlagetabelle" macht den Vergleich schnell.
var alt = csv.parse("Name\nBäckerei Schmitz\nAutohaus Weber\nBlumen Meyer", { header: true });
var neu = csv.parse("Name\nBäckerei Schmitz\nBlumen Meyer\nCafé Sommer", { header: true });
function namen(liste) {
var set = {};
liste.forEach(function (z) { set[z.Name] = true; });
return set;
}
var altSet = namen(alt), neuSet = namen(neu);
neu.forEach(function (z) { if (!altSet[z.Name]) log.info("neu: " + z.Name); });
alt.forEach(function (z) { if (!neuSet[z.Name]) log.info("entfallen: " + z.Name); });
25. Aufräumen¶
Löscht den Übungsordner samt Inhalt.