CSV Datei einlesen
Freak
- programmiertechnik
Hi,
ich lese immer wieder mal eine CSV-Datei in meine Datenbank ein. Ist soweit kein Problem.
Jatzt habe ich aber eine CSV-Datei bekommen, die nicht einen Datensatz per Zeile hat, sondern immer wieder auch mal eine Zeile, bei der der Inhalt eines Feldes mehrzeilig ist.
Als Beispiel:
1|2|3|4
a|b|c|d
pi|mal
daumen
ist prima|na|sowas
q|w|e|r
Wie lese ich denn die ein?
Freak
Jatzt habe ich aber eine CSV-Datei bekommen, die nicht einen Datensatz per Zeile hat, sondern immer wieder auch mal eine Zeile, bei der der Inhalt eines Feldes mehrzeilig ist.
Als Beispiel:
1|2|3|4
a|b|c|d
pi|mal
daumen
ist prima|na|sowas
q|w|e|rWie lese ich denn die ein?
So, wie bisher auch, nur, dass du die Suche nach dem Datensatzende selbst übernehmen musst, anstatt eine Funktion zu nutzen, die ganze Zeilen zurückgibt (lies: selbst nach dem Zeilenende sucht):
1. Datensatz anlegen
2. Spaltenzeiger auf Spalte 1
3. Ein Zeichen lesen
4. a) Falls Dateiende, dann Datensatz speichern und Programmende
b) Falls |, dann Spaltenzeiger auf nächste Spalte
ba) Falls Spaltenzeiger > Spaltenanzahl, dann Datensatz speichern und weiter bei 1.
c) Falls nicht |, dann Zeichen an aktuelle Spalte anhängen
3. Weiter bei 3.
Ganz einfach.
So, wie bisher auch, nur, dass du die Suche nach dem Datensatzende selbst übernehmen musst, anstatt eine Funktion zu nutzen, die ganze Zeilen zurückgibt
Hi Friedhelm,
danke Dir.
Mir gings jetzt nurmal darum, ob es da noch Möglichkeiten gibt, die ich noch nicht kenne, aber dem scheint (Deiner Antwort zufolge) nicht so zu sein .
Aber mir gleich die komplette Funktion mitzuliefern ist wirklich nett, dafür einen extra Dank an Dich.
Freak
Hello,
Jatzt habe ich aber eine CSV-Datei bekommen, die nicht einen Datensatz per Zeile hat, sondern immer wieder auch mal eine Zeile, bei der der Inhalt eines Feldes mehrzeilig ist.
Als Beispiel:
1|2|3|4
a|b|c|d
pi|mal
daumen
ist prima|na|sowas
q|w|e|rWie lese ich denn die ein?
So, wie bisher auch, nur, dass du die Suche nach dem Datensatzende selbst übernehmen musst, anstatt eine Funktion zu nutzen, die ganze Zeilen zurückgibt (lies: selbst nach dem Zeilenende sucht):
Eben nicht!
Wenn denn unbedingt PHP zwischengeschaltet sein soll, sollte er die Funktion fgetcsv() benutzen und die Funktionsargumente richtig einstellen. Dann erhält er jeden Datensatz als Array. Jedes Element des Arrays kann dann auch Trennzeichen (z.B. Semikolon) und Zeilenendezeichen (z.B. \r\n) enthalten.
Die passende Vorbehandlung der Elemente für die Datenbank muss beachtet werden!
siehe
http://de3.php.net/manual/en/function.fgetcsv.php
und
http://wiki.selfhtml.org/wiki/Artikel:Kontextwechsel
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Wenn denn unbedingt PHP zwischengeschaltet sein soll, sollte er die Funktion fgetcsv() benutzen und die Funktionsargumente richtig einstellen. Dann erhält er jeden Datensatz als Array. Jedes Element des Arrays kann dann auch Trennzeichen (z.B. Semikolon) und Zeilenendezeichen (z.B. \r\n) enthalten.
Ist ja noch besser, Tom.
Also mal nachsehen, ob es eine "echte CSV" ist.
Eine Randfrage dazu: Wie muß ich in php selber beim CSV-Export das Zeilenende definieren, damit meine Daten "echte CSVs" werden?
Wie würde ich eine Zeile in eine Export-CSV schreiben, die sowohl Zeilenumbrüche innerhalb einer Spalte als auch Zeilenendezeichen enthalten?
Die passende Vorbehandlung der Elemente für die Datenbank muss beachtet werden!
Du meinst die Maskierung?
Inwiefern ist der Kontextwechsel hier wichtig? Nur ich arbeite mit der Datei und auch das nur 1 mal.
VG, Freak
Tach!
Eine Randfrage dazu: Wie muß ich in php selber beim CSV-Export das Zeilenende definieren, damit meine Daten "echte CSVs" werden?
Nimm die von PHP für das Schreiben von CSV-Dateien zur Verfügung gestellten Funktionen (z.B. fputcsv()). Wenn dein PHP zu alt ist, findest du auch fertige Nachbauten im Netz.
Wie würde ich eine Zeile in eine Export-CSV schreiben, die sowohl Zeilenumbrüche innerhalb einer Spalte als auch Zeilenendezeichen enthalten?
Diese und Folgefragen sind bereits in der Wikipedia beantwortet: http://de.wikipedia.org/wiki/CSV_(Dateiformat) (zweiter Abschnitt)
Inwiefern ist der Kontextwechsel hier wichtig? Nur ich arbeite mit der Datei und auch das nur 1 mal.
Dessen Beachtung ist immer wichtig. Du kannst nur dann Maßnahmen unterlassen, wenn du die Daten genau kennst, sprich: wenn sie als Literal im Code stehen und definitiv keine Maskierungen benötigen.
dedlfix.
Hello,
Inwiefern ist der Kontextwechsel hier wichtig? Nur ich arbeite mit der Datei und auch das nur 1 mal.
Dessen Beachtung ist immer wichtig. Du kannst nur dann Maßnahmen unterlassen, wenn du die Daten genau kennst, sprich: wenn sie als Literal im Code stehen und definitiv keine Maskierungen benötigen.
Und selbst das muss ja nicht von Bestand sein. Es könnte ja sein, dass dem jeweiligen Datenbankhersteller plötzlich einfällt, dass er ein Zeichen, das bisher vollkommen unkritisch war, für Sonderzwecke einsetzen will - rein hypothetisch, versteht sich!
Wenn die zur Datenbankschnittstelle Maskierungsfunktion das dann auch berücksichtigt, wovon ich ausgehe, muss der Programmierer der Applikation nicht weiter tun, als sein Programm neu kompilieren zu lassen, oder bei den Interpretersprachen eben das passende Update des Interpreters durchzuführen.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
So, wie bisher auch, nur, dass du die Suche nach dem Datensatzende selbst übernehmen musst, anstatt eine Funktion zu nutzen, die ganze Zeilen zurückgibt (lies: selbst nach dem Zeilenende sucht):
Eben nicht!
Oh. Ein Hellseher. Mit Ausrufungszeichen.
Wenn denn unbedingt PHP zwischengeschaltet sein soll, sollte er die Funktion fgetcsv() benutzen
Ich kann jetzt nicht nachvollziehen, wie du darauf kommst, dass sich aus der Themenangabe "Programmiertechnik" zwangsläufig die Sprache PHP ergibt, oder inwiefern du den Einsatz einer PHP-Funktion unter beispielsweise C oder Python für sinnvoll hältst.
Von PHP (oder sonst einer Sprache) war jedenfalls nirgends die Rede.
Hello,
So, wie bisher auch, nur, dass du die Suche nach dem Datensatzende selbst übernehmen musst, anstatt eine Funktion zu nutzen, die ganze Zeilen zurückgibt (lies: selbst nach dem Zeilenende sucht):
Eben nicht!
Oh. Ein Hellseher. Mit Ausrufungszeichen.
Wenn denn unbedingt PHP zwischengeschaltet sein soll, sollte er die Funktion fgetcsv() benutzen
Ich kann jetzt nicht nachvollziehen, wie du darauf kommst, dass sich aus der Themenangabe "Programmiertechnik" zwangsläufig die Sprache PHP ergibt, oder inwiefern du den Einsatz einer PHP-Funktion unter beispielsweise C oder Python für sinnvoll hältst.
Na, wenn denn eine andere Programmiersprache in einer API dazwischengeschaltet sein soll, muss er selbstverständlich die passende Funktion aus dieser Sprache nutzen, oder sich eben eine schreiben.
Was dabei zu beachten ist, habe ich hier https://forum.selfhtml.org/?t=211028&m=1439709 erwähnt.
Von PHP (oder sonst einer Sprache) war jedenfalls nirgends die Rede.
Wenn von keiner Sprache die Rede ist, wird hier i. d. R. von PHP > 5.x ausgegangen
Wenn von keiner Datenbank die Rede ist, wird hier i. d. R. von MySQL > 5.x ausgegangen
Wenn von keinem Webserver die Rede ist, wird hier i. d. R. von einem neueren Apache ausgegangen
Früher stand das auch mal irgendwo. Ich gestehe, dass ich jetzt zu faul bin, danach zu suchen.
Sind der Herr Professor nun zufrieden? :-P
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hi,
Jatzt habe ich aber eine CSV-Datei bekommen, die nicht einen Datensatz per Zeile hat, sondern immer wieder auch mal eine Zeile, bei der der Inhalt eines Feldes mehrzeilig ist.
Als Beispiel:
1|2|3|4
a|b|c|d
pi|mal
daumen
ist prima|na|sowas
q|w|e|rWie lese ich denn die ein?
Wende dich an den Anbieter der Datei, und verlange „richtiges“ CSV.
Bei mehrzeiligen Inhalten ist die übliche Konvention, diese in "-Zeichen einzukleiden – das kann dann bspw. auch fgetcsv problemlos einlesen, und man muss sich nichts selber basteln.
MfG ChrisB
Wende dich an den Anbieter der Datei, und verlange „richtiges“ CSV.
Bei mehrzeiligen Inhalten ist die übliche Konvention, diese in "-Zeichen einzukleiden – das kann dann bspw. auch fgetcsv problemlos einlesen, und man muss sich nichts selber basteln.
Danke für den Hinweis, ChrisB.
Der Anbieter bin ich sozusagen selber, ich exportiere aus ein er fremden Software, aber die bietet an, die Felder in " einzukleiden, was ich abgelehnt habe.
Ich wußte bisher nicht, wozu das dient. ;-)
Freak
Hello,
Wende dich an den Anbieter der Datei, und verlange „richtiges“ CSV.
Bei mehrzeiligen Inhalten ist die übliche Konvention, diese in "-Zeichen einzukleiden – das kann dann bspw. auch fgetcsv problemlos einlesen, und man muss sich nichts selber basteln.
Danke für den Hinweis, ChrisB.
Der Anbieter bin ich sozusagen selber, ich exportiere aus ein er fremden Software, aber die bietet an, die Felder in " einzukleiden, was ich abgelehnt habe.
Ich wußte bisher nicht, wozu das dient. ;-)
Das muss die Sache auch nicht unbedingt verbessern.
Die Grundregeln für CSV lauten:
Datenfelder werden durch einen FELDTRENNER abgetrennt.
Datensätze werden durch DATENSATZENDEZEICHEN ("Zeilenumbruch") begrenzt
Wenn der Feldtrenner auch innerhalb von Datenfeldern auftreten soll, dann müssen die Felder durch FELDBEGRENZUNGSZEICHEN eingeschlossen werden.
Wenn das DATENSATZENDEZEICHEN auch innerhalb von Datenfeldern auftreten soll, dann müssen die Felder durch FELDBEGRENZUNGSZEICHEN eingeschlossen werden.
Wenn das FELDBEGRENZUNGSZEICHEN auch innerhalb eines Datenfeldes auftreten soll, dann muss es bei jedem Auftreten innerhalb des Feldes verdoppelt werden.
Diese Regeln zeigen aber auch ganz deutlich, dass CSV-Dateien ausschließlich sequentiell gelesen werden können.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hello,
ich lese immer wieder mal eine CSV-Datei in meine Datenbank ein. Ist soweit kein Problem.
Jatzt habe ich aber eine CSV-Datei bekommen, die nicht einen Datensatz per Zeile hat, sondern immer wieder auch mal eine Zeile, bei der der Inhalt eines Feldes mehrzeilig ist.
Als Beispiel:
1|2|3|4
a|b|c|d
pi|mal
daumen
ist prima|na|sowas
q|w|e|r
Wie sieht der Datenstrom denn in der Hexadezimaldarstellung aus?
Die Darstellung im Editor unterliegt den Regeln für Textdateien und nicht denen für Datendateien. Ein Editor ist als meistens das falsche Werkzeug, um eine Datendatei zu analysieren!
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hi Tom,
Wie sieht der Datenstrom denn in der Hexadezimaldarstellung aus?
Wenn ich wüßte, wie ich ihn interpretieren muss, könnte ich Dir das sagen.
:-(
Freak
Hi Tom,
Wie sieht der Datenstrom denn in der Hexadezimaldarstellung aus?
Es sieht so aus, als würden die Zeilenenden mit 0D0A gesetzt, egal ob der Datensatz oder nur die Zeile beendet wird.
Hello,
Wie sieht der Datenstrom denn in der Hexadezimaldarstellung aus?
Es sieht so aus, als würden die Zeilenenden mit 0D0A gesetzt, egal ob der Datensatz oder nur die Zeile beendet wird.
Ja, das ist normal. Nun solltest Du uns mal einen Ausschnitt aus der Datei zur Verfügung stellen, der mindestens drei Datensätze umfasst. Und diesen Ausschnitt solltest Du in Hexadezimaldarstellung liefern.
Alternativ kannst Du feststellen, ob die Feldanzahl pro Datensatz konstant ist, auch wenn Felder leer sind. Dann stehen eben zwei reservierte Feldtrenner direkt hintereinander. Es hilf Dir dann die Abzählmethode, um die sequentielle Datei in eine andere Form (z.B. ramdom access) zu bringen.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Alternativ kannst Du feststellen, ob die Feldanzahl pro Datensatz konstant ist, auch wenn Felder leer sind.
Hi Tom,
habe schon festgestellt. Im Handbuch steht ja der folgende nette Code, der mir dabei hilft
$row = 1;
if (($handle = fopen("test.csv", "r")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, "|")) !== FALSE) {
$num = count($data);
echo "<b> $num Felder in Zeile $row: <br /></b>\n";
$row++;
for ($c=0; $c < $num; $c++) {
echo $data[$c] . "<br />\n";
}
}
fclose($handle);
}
In Summe weiß ich nun, wo der "Fehler" liegt. Ich sollte beim Export die Felder in " fassen, dann wird es interpretiert werden können.
Freak
In Summe weiß ich nun, wo der "Fehler" liegt. Ich sollte beim Export die Felder in " fassen, dann wird es interpretiert werden können.
Die Vermutung war schon ganz ok, aber es tut sich eine andere Frage auf. Was mache ich mit den "-Zeichen, die innerhalb eines Feldes enthalten sind, bzw. wie kann ich diese escapen, wenn es die "Exportsoftware" es nicht selber beim Export macht?
Freak
Tach!
Die Vermutung war schon ganz ok, aber es tut sich eine andere Frage auf. Was mache ich mit den "-Zeichen, die innerhalb eines Feldes enthalten sind, bzw. wie kann ich diese escapen, wenn es die "Exportsoftware" es nicht selber beim Export macht?
Die erste Teilfrage ist bereits beantwortet. Wenn die Export-Software Anführungszeichen in den Nutzdaten nicht korrekt behandelt, dann kannst du nichts weiter machen, als mit Intelligenz und zu Fuß den Fehler zu korrigieren. Die Alternative wäre, dass du die Feldtrennzeichen einzeln zählst und daran die Grenzen festmachst. Das klappt nur nicht, wenn im letzten Feld Zeilenumbruch vorkommt.
Letztlich ist es immer das gleiche Prinzip. Du kannst nichts ordentlich dekodieren, wenn es nicht ordentlich kodiert wurde.
dedlfix.
Hello,
Die Vermutung war schon ganz ok, aber es tut sich eine andere Frage auf. Was mache ich mit den "-Zeichen, die innerhalb eines Feldes enthalten sind, bzw. wie kann ich diese escapen, wenn es die "Exportsoftware" es nicht selber beim Export macht?
Die erste Teilfrage ist bereits beantwortet.
die zweite auch: https://forum.selfhtml.org/?t=211028&m=1439709
Wenn die Export-Software Anführungszeichen in den Nutzdaten nicht korrekt behandelt, dann kannst du nichts weiter machen, als mit Intelligenz und zu Fuß den Fehler zu korrigieren. Die Alternative wäre, dass du die Feldtrennzeichen einzeln zählst und daran die Grenzen festmachst.
Genau. Das klappt, wenn das Feldtrennzeichen geschützt ist, also nicht in den Daten auftauchen darf und wenn es sich um Datensätze mit fester Feldanzahl handelt. Dann hilft die Abzählmethode immer, egal wo da Zeilenumbrüche vorkommen.
https://forum.selfhtml.org/?t=211028&m=1439702
Das klappt nur nicht, wenn im letzten Feld Zeilenumbruch vorkommt.
Das ist egal, wenn oben erwähntes dafür zutrifft.
Letztlich ist es immer das gleiche Prinzip. Du kannst nichts ordentlich dekodieren, wenn es nicht ordentlich kodiert wurde.
Ack
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Tach!
Genau. Das klappt, wenn das Feldtrennzeichen geschützt ist, also nicht in den Daten auftauchen darf und wenn es sich um Datensätze mit fester Feldanzahl handelt. Dann hilft die Abzählmethode immer, egal wo da Zeilenumbrüche vorkommen.
Das klappt nur nicht, wenn im letzten Feld Zeilenumbruch vorkommt.
Das ist egal, wenn oben erwähntes dafür zutrifft.
Nö. Wie willst du denn wissen, ob
a|b|c
d
e|f|g
d nun zu c oder e gehört?
dedlfix.
Hello,
Genau. Das klappt, wenn das Feldtrennzeichen geschützt ist, also nicht in den Daten auftauchen darf und wenn es sich um Datensätze mit fester Feldanzahl handelt. Dann hilft die Abzählmethode immer, egal wo da Zeilenumbrüche vorkommen.
Das klappt nur nicht, wenn im letzten Feld Zeilenumbruch vorkommt.
Das ist egal, wenn oben erwähntes dafür zutrifft.Nö. Wie willst du denn wissen, ob
a|b|c
d
e|f|gd nun zu c oder e gehört?
*ups*
Stimmt. Funktioniert nur so leidlich, wenn jedes Feld durch den geschützten Feldtrenner beendet wird.
Dann darf man einen Zeilenumbruch nach X Feldtrennern als solchen ansehen und aus den Nutzdaten entfernen und muss ihn nicht dem nächsten Feldinhalt zurechnen.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Tach!
Wie sieht der Datenstrom denn in der Hexadezimaldarstellung aus?
Wenn ich wüßte, wie ich ihn interpretieren muss, könnte ich Dir das sagen.
Man nehme sich die zur verwendeten Kodierung verfügbaren Kodiertabellen, zum Beispiel: ISO-8859-1. Wenn es UTF-8 ist, reicht in dem speziellen Fall auch eine ASCII-Tabelle, weil die Zeichen oberhalb von 7F hier nicht relevant sind.
dedlfix.