Probleme beim Einlesen einer CSV Datei in ein 2dArray.



  • Hallo Freunde! Ich bin leider schon wieder auf eure Hilfe angewiesen!
    Ich komme hier leider nicht weiter!
    Folgendes:
    Ich habe eine Große CSV. datei (Komma Separated VAlues)

    abcd,abcd,abdc,.....,abcd
    12.34,12.34,12.34,.....,12.34
    .........,.........,.........,......,.........
    12.34,12.34,12.34,.....,12.34

    Bekannt sind die Variablen Spalten und Zeilen
    Das Ganze soll in ein 2darray eingelesen werden. Das 2d Array ist vorher initialisiert.
    Hier ist die Funktion die das Array füllen soll.

    void store_csv (int **csv_array, int *check char *dateiname){
    
    	FILE * pFile;
    	pFile=fopen (dateiname,"r");
    
    	int zeile = 0;
    	int spalte = 0;
    
    	int c=0;
    	int n=0;
    	float wert1=0;
    
    Zeilen = check[0];
    Spalten = check[1]*check[2];
    
    	printf ("\n(test)Spalten:%i ",Spalten); //TEST ok!
    	printf ("\n(test)Zeilen:%i ",Zeilen);   //TEST ok!
    
    char * buffer;
    
    //Zeichen in Zeile 1 zählen. Zeile 1 ist immer die längste Zeile.
    while(c!='\n'){ 
        c = fgetc (pFile);
        n++;
    }
    char line[n];
    	printf ("\n(test)Zeichen in Zeile 1:%i ",n); //TEST ok!
    
    rewind(pFile);
    
    while (getline (pFile, line)){
    			while (buffer = strtok (line,",")){  //Schleife zum Einlesen von Zeile 1
    			if(zeile<1){
    				csv_array[zeile][spalte] = 0;
    				printf("\nBuffer:%c",buffer);
    				if (spalte>10)exit(0);		//temp
    					if ((zeile>Zeilen) ||(spalte>Spalten)){
    					printf("\nSpeicherzugriffsfehler bei dem Einlesen der CSV datei");
    					printf("\n in linie 0 zeile:%i    spalte:%i",zeile,spalte);
    				}
    			spalte++;
    			}
    
    			else{   //Schleifre zum Einlesen der restlichen Zeilen
    				wert1 = (float)*buffer;
    				wert1 = wert1*100;
    				if ((zeile>Zeilen) ||(spalte>Spalten)){
    					printf("\nSpeicherzugriffsfehler bei dem Einlesen der CSV datei");
    					printf("\nzeile:%i    spalte:%i",zeile,spalte);
    				}
    				csv_array[zeile][spalte] = wert1;
    				printf("\nwert:%i",wert1/100);
    			spalte++;
    			}
    
    		}
    		spalte=0;
    		zeile++;
    	}
    	fclose(pFile); 
    }
    

    Zur Zeit scheitert es daran dass die while-Schleifen endlos laufen und kein Einziger Wert eingelesen wird!
    Vielen Dank für eure Ideen!
    Gruß,
    Lin



  • Hallo Freund,

    ohje, das geht doch viel kürzer und unkomplizierter 😉

    Was mir aufgefallen ist:

    • Zeile 4: Du solltest den Rückgabewert von fopen überprüfen.
    • Zeile 33: Stimm das getline wirklich? Wenn getline am Ende ist, ist der Rückgabewert EOF . Außerdem braucht getline scheinbar 3 Argumente. Siehe hier. Kann natürlich sein, dass es auch anders implementiert wurde.
    • Zeile 34 ff.: strtok wird nicht ganz korrekt angewendet. Beim ersten 'split' ist das erste Argument die Zeichenkette; Bei den folgenden jedoch NULL . Siehe hier.
    • Zeile 47: So geht das aber nicht. Hierfür würde ich entweder strtol oder atoi verwenden.

    Die Schleife in Zeile 23 zählt übrigens das '\n' mit, da inkrementiert wird, ohne das Zeichen zu überprüfen. Richtig wäre:

    ...
    while ((c = fgetc (file)) != '\n') n++;
    ...
    

    Die Schleife ab Zeile 33 würde ich in etwa so machen:

    ...
    while (fgets (buffer, line_max, file) && zeile < Zeilen) {
        spalte = 0;
        // deine if-Abfage bzgl. der Zeile
        if (zeile == 0) {
            ...
        } else {
            str = strtok (buffer, ",");
            while (str != NULL && spalte++ < Spalten) {
                arr[zeile][spalte] = atoi (str);
                str = strtok (NULL, ",");
            }
        }
        zeile++;
    }
    ...
    

    Gez. monstermunchkin



  • Danke für deine Hinweise!
    ich würde gerne mit strings arbeiten aber mein Compiler (Gnu C Compiler) kennt keine strings!

    String str;
    

    kennt er nicht!
    hier sind meine Includes: fehlt da was?

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    #include <termios.h>
    #include <unistd.h>
    #include <memory.h>
    

    Ich möchte von jedem Wert 2 Kommastellen einlesen deswegen mein :wert1=(float)*buffer; und wert1=wert1*100.
    Wenn ich diesen Wert als in mein Integer Array einlese habe ich alle ´Kommastellen die ich brauche!



  • lin123 schrieb:

    Danke für deine Hinweise!
    ich würde gerne mit strings arbeiten aber mein Compiler (Gnu C Compiler) kennt keine strings!

    String str;
    

    kennt er nicht!

    C kennt keine Strings, nur Character-Arrays. Daran sollte es aber wirklich nicht scheitern 😉

    lin123 schrieb:

    hier sind meine Includes: fehlt da was?

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    #include <termios.h>
    #include <unistd.h>
    #include <memory.h>
    

    Weiß zwar nicht wie Dein gesamtes Programm aussieht, aber für die Einlesefunktion benötigst du nur die oberen drei.

    lin123 schrieb:

    Ich möchte von jedem Wert 2 Kommastellen einlesen deswegen mein :wert1=(float)*buffer; und wert1=wert1*100.
    Wenn ich diesen Wert als in mein Integer Array einlese habe ich alle ´Kommastellen die ich brauche!

    Sorry, hatte übersehen, dass in der csv-Datei Fließkommazahlen stehen. In dem Fall kannst du entwender atof oder strtod verwenden. Was auch möglich wäre, ist sscanf , vor allem dann, wenn in der csv-Datei mehr Nachkommastellen stehen, als du eigentlich brauchst bzw. einlesen möchtest.
    WICHTIG: Du kannst keine Fließkommazahlen in einem int -Array speichern! Verwende doch einfach ein double - oder float -Array.



  • ansi c kennt den datentypen string nicht und die funktion getline ist nicht standard!



  • lin123 schrieb:

    Ich habe eine Große CSV. datei (Komma Separated VAlues)

    wieso speicherst du da extra kommas zwischen die werte, das ist doch gerade bei großen dateien ineffizient 👎



  • schlank0r schrieb:

    lin123 schrieb:

    Ich habe eine Große CSV. datei (Komma Separated VAlues)

    wieso speicherst du da extra kommas zwischen die werte, das ist doch gerade bei großen dateien ineffizient

    weil es ein weit verbreitetes format ist, das viele programme verstehen.
    was würdest du denn zwischen die werte packen, damit es 'effizienter' wird?
    🙂



  • ich würde einfach nichts dazwischen packen(braucht man ja auch nicht) und dann blockweise mit fread einlesen



  • also im binärmodus speichern würd ich das, dann entfällt auch die ineffiziente konvertierung von string nach double.



  • @schlank0r
    Die Kommas speichere ich doch nicht in meinem Array? ich verstehe nicht ganz was du meinst!
    Die csv datei ist mein Eingangsformat, da will ich nix dran ändern!

    @monstermunchkin
    Ja, das mit Float Array würd gehen aber die csv Datein sind bis zu 1Gb groß. Deswegen denke ich, wenn ich das array als int initialisiere, mein Programm deutlich weniger Arbeitsspeicher verwenden wird!

    Wenn ich statt str ein char array nehme, muss ich das mit einer bestimmten größe initialisieren?

    den char array "buffer" habe ich ja auch nicht mit einer bestimmten Länge angelegt, ist das nicht auch problematisch?



  • lin123 schrieb:

    Ja, das mit Float Array würd gehen aber die csv Datein sind bis zu 1Gb groß. Deswegen denke ich, wenn ich das array als int initialisiere, mein Programm deutlich weniger Arbeitsspeicher verwenden wird!

    float und int haben beide jeweils 4 Byte. Aber das kannst du machen wie du möchtest.

    lin123 schrieb:

    Wenn ich statt str ein char array nehme, muss ich das mit einer bestimmten größe initialisieren?
    den char array "buffer" habe ich ja auch nicht mit einer bestimmten Länge angelegt, ist das nicht auch problematisch?

    Kommt drauf an, was man vorhat. Das mit buffer ist schon richtig so.



  • Das Einlesen funktioniert soweit
    hier ist der Code:

    while (fgets (buffer, line_max, pFile) && zeile < Zeilen) { 
        spalte = 0; 
        if (zeile == 0) {
        	for (spalte=0; spalte<Spalten; spalte++){
        		csv_array[zeile][spalte] = 0; 
         	}
        	printf ("(test3)\n");
        } else {
            str = strtok (buffer, ","); 
            while (str != NULL && spalte++ < Spalten) { 
                csv_array[zeile][spalte] = atoi (str); 
                str = strtok (NULL, ","); 
            } 
        } 
        zeile++; 
    }
    

    Allerdings ergibt sich
    csv_array[zeile][0]=0
    csv_array[zeile][1]=Wert der ersten Spalte in der CSV
    der Erste Wert von Spalte ist doch 0 und nicht 1!



  • lin123 schrieb:

    Das Einlesen funktioniert soweit
    hier ist der Code:

    while (fgets (buffer, line_max, pFile) && zeile < Zeilen) { 
        spalte = 0; 
        if (zeile == 0) {
        	for (spalte=0; spalte<Spalten; spalte++){
        		csv_array[zeile][spalte] = 0; 
         	}
        	printf ("(test3)\n");
        } else {
            str = strtok (buffer, ","); 
            while (str != NULL && spalte++ < Spalten) { 
                csv_array[zeile][spalte] = atoi (str); 
                str = strtok (NULL, ","); 
            } 
        } 
        zeile++; 
    }
    

    Allerdings ergibt sich
    csv_array[zeile][0]=0
    csv_array[zeile][1]=Wert der ersten Spalte in der CSV
    der Erste Wert von Spalte ist doch 0 und nicht 1!

    Okay!! in der while schleife wird spalte bereits erhöht!



  • lin123 schrieb:

    Ich möchte von jedem Wert 2 Kommastellen einlesen deswegen mein :wert1=(float)*buffer; und wert1=wert1*100.

    Das wird so nicht gehen. Der schneidet Dir zuerst die Nachkommastellen ab und multipliziert dann mit 100. D. h. wenn buffer = 3.14 dann wert1 = 300 .
    EDIT 1: Gerade nochmal getestet: Der gibt Dir den ASCII-Wert von 3 zurück, also 51, und multipliziert dann mit 100.

    int wert1;
    wert1 = atof (buffer) * 100; // so ist's richtig
    


  • lin123 schrieb:

    Die csv datei ist mein Eingangsformat, da will ich nix dran ändern!

    doofes format bei so großen dateien



  • schlank0r schrieb:

    lin123 schrieb:

    Die csv datei ist mein Eingangsformat, da will ich nix dran ändern!

    doofes format bei so großen dateien

    garnicht. bei kleinen werten wirds sogar weniger.
    🙂



  • ;fricky schrieb:

    garnicht. bei kleinen werten wirds sogar weniger.
    🙂

    achwas.
    klein: 0.0000001
    😃



  • außerdem muss bei csv dateien zusätzlich noch konvertiert werden.
    vielleicht hat ja jemand mal lust nen test mit 1GB nutzdaten zu machen



  • schlank0r schrieb:

    außerdem muss bei csv dateien zusätzlich noch konvertiert werden.

    das muss immer sein, wenn ein allgemeines 'kanonisches' textformat verwendet wird. vorteil eines textformats ist ausserdem, dass es menschenlesbar ist, dass man's mit jedem editor bearbeiten kann, dass es keine steuerzeichen enthält, die programme verwirren könnten, usw. fast jede schäbige datenbank oder tabellenkalkulation kann CSV importieren. komprimieren lässt es sich auch sehr gut. binärformate sind eigentlich immer dann toll, wenn man nur sehr wenig rechenleistung, speicherplatz oder bandbreite hat. sonst sind textformate einfach viel praktischer (sogar XML und sowas).
    🙂



  • ja, ich lese auch ganz gern mal 1GB double werte quer.
    🙂


Log in to reply