Freak: CSV Datei einlesen

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

  1. 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?

    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.

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

    2. 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|r

      Wie 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

      --
       ☻_
      /▌
      / \ Nur selber lernen macht schlau
      http://bergpost.annerschbarrich.de
      1. 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

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

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

            --
             ☻_
            /▌
            / \ Nur selber lernen macht schlau
            http://bergpost.annerschbarrich.de
      2. 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.

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

          --
           ☻_
          /▌
          / \ Nur selber lernen macht schlau
          http://bergpost.annerschbarrich.de
  2. 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|r

    Wie 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

    --
    RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?
    1. 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

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

        --
         ☻_
        /▌
        / \ Nur selber lernen macht schlau
        http://bergpost.annerschbarrich.de
  3. 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

    --
     ☻_
    /▌
    / \ Nur selber lernen macht schlau
    http://bergpost.annerschbarrich.de
    1. 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

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

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

          --
           ☻_
          /▌
          / \ Nur selber lernen macht schlau
          http://bergpost.annerschbarrich.de
          1. 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

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

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

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

                  --
                   ☻_
                  /▌
                  / \ Nur selber lernen macht schlau
                  http://bergpost.annerschbarrich.de
                  1. 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.

                    1. 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|g

                      d 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

                      --
                       ☻_
                      /▌
                      / \ Nur selber lernen macht schlau
                      http://bergpost.annerschbarrich.de
      2. 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.