C - CSV einlesen

Hey Guys…

sitze vor folgendem Problem.
Sitze aktuell gerade an einen C Projekt und muss mich erst ein wenig einfuchsen. Ich versuche gerade das das Programm mir eine CSV-Datei einliest und die durch komma getrennten Werte in ein Array schreibt.

Die CSV-Datei geöffnet sieht so aus:

„41.7“,„38.3“,„36.3“,„45.4“
„43.5“,„42.4“,„56.4“,„47.9“
„53.6“,„61.4“,„60.1“,„63.2“
„61.7“,„55.0“,„53.7“,„53.6“
„56.1“,„55.8“,„53.1“,„52.6“
„54.5“,„56.6“,„61.5“,„61.8“
.
.
.

Hier mein bisheriger Versuch es mit C zu Programmieren.
Bitte reisst mir nicht den Kopf, bin absoluter Anfänger und falls die eine oder andere Sache vieleicht net der soo perfekte Programmierstil ist bitte ich das zu etnschuldigen :smile:
Als Programmierbasis benutze ich DEVc++

Das C-Programm

#include
#include

int main(void)
{
FILE *data;
char *filename;
char c;
int ZV=0,i =0,ZV1=0;
int* Array;
char string=0;

printf(„Bitte nennen Sie die Datei zum einlesen:\n“);
scanf("%s",filename);
data = fopen(filename, „r“);

if (data!=NULL)
{
while ((c=fgetc(data))!=EOF)
{
if (c==’,’) {ZV++;}
if (c==’\n’) {ZV++;}
}
}
else { printf(„Fehler beim Oeffnen der Datei!\n“);}
//Feld benötigter Groesse wird erstellt
Array = (int*)malloc(ZV * sizeof(int));

for(ZV1=ZV;ZV1>0;ZV1–)
{
i=0;
fscanf(data,"%d.%d", &string);
*(Array+i)=string1;
i++;
}
for (ZV1=ZV;ZV1>0;ZV1–)
{
i=0;
printf("%s %d\n", (Array+i),i);
i++;
}

printf(„Die Datei enthaelt %d Felder\n“, ZV);
free (Array);
system(„PAUSE“);
return 0;
}

Was mache ich falsch? Warum funktioniert es nicht?
Als ausgabe bekomme ich so in jeden Feld 0
Warum???

Ich hoffe ihr könnt mir helfen :smile:
Greez
Alex

Hallo,

data = fopen(filename, „r“);

if (data!=NULL)
{
while ((c=fgetc(data))!=EOF)

for(ZV1=ZV;ZV1>0;ZV1–)
{
i=0;
fscanf(data,"%d.%d", &string);
*(Array+i)=string1;
i++;
}

Was mache ich falsch?

Du liest bis zum Ende der Datei, und danach noch weiter - da bist du aber bereits am Ende der Datei.

Du kannst die Position innerhalb der Datei mit seek() zuruecksetzen.

Gruesse,
Moritz

Hi,

mal eine Version mit minimalem Parser, also lese bis ", lese eine Kommazahl, lese ", überspringe Trennzeichen, zurück zu Anfang. Damit muss dann die Datei nur einmal gelesen werden.

Den Speicher habe ich mit realloc reserviert und dynamisch vergrößert, dass das in 10er-Schritten passiert ist nur für Demonstrationszwecke gedacht, passender wäre 200. Konsultiere das Beispiel in
http://www.cplusplus.com/reference/clibrary/cstdlib/…
um Fehler dabei abzufangen, wenn die Datenmengen wirklich größer werden.

Als weitere Übung könnte man noch die Kommandozeilenargumente abfragen und nur interaktiv nach dem Dateinamen fragen, wenn auf der Kommandozeile nichts angegeben wurde. Das erleichtert u.a. das Testen.

Gruß Lutz

#include 
#include 

int main(void)
{
 FILE \*data;
 char filename[150];
 int ZV=0,i =0;
 double\* Array=NULL;
 int limit=0;

 printf("Bitte nennen Sie die Datei zum einlesen:\n");
 scanf("%s", filename);
 data = fopen(filename, "r");

 if (data==NULL)
 {
 printf("Fehler beim Oeffnen der Datei!\n");
 exit(-1);
 }

 while(!feof(data))
 {
 char c;
 if(i==limit){
 //Feld wird erstellt oder vergroessert
 limit+=10;
 Array=(double\*)realloc(Array,limit \* sizeof(double));
 }
 /\* Lese bis Doppelstrich \*/
 while(fgetc(data)!='\"')putchar('.');
 /\* Lese Zahl mit Nachkommastellen \*/
 fscanf(data,"%lf", Array+i);
 /\* Lese bis Doppelstrich \*/
 while(fgetc(data)!='\"')putchar(',');
 /\* Ueberspringe Leer- und Trennzeichen \*/
 do{ c=fgetc(data); } while((c==' ')||(c==',')||(c=='\n'));
 ungetc(c,data);
 /\* Position hochzaehlen \*/
 i++;
 }
 /\* letzten Zaehlerstand speichern \*/
 ZV=i;
 /\* Kontrollausgabe \*/
 for (i=0; i

Hi Alex,

auch von mir noch einige Anmerkungen:

  • Um die Größe der Datei zu erfahren, kannst Du die Funktionen fseek und ftell verwenden – mit fseek gehst Du ans Ende der Datei, mit ftell erhältst Du dann die Anzahl der Bytes, die Du vom Dateianfang entfernt bist. Anschliessend musst Du mit fseek wieder an den Anfang springen, um dann einlesen zu können.
    (Doku zu den Funktionen: http://www.cplusplus.com/reference/clibrary/cstdio/)

  • In Deinen for-Schleifen setzt Du die Varable i auf Null, und zwar bei jedem Schleifendurchlauf. Deshalb gibst Du mit Deinem printf-Aufruf auch nur Nullen aus.
    Um i am Anfang, des Schleifendurchlauf auf Null zu setzen, kannst Du es mit in die Klammern aufnehmen:

for ( V1=ZV, i=0 ; ZV1 > 0 ; ZV1-- ) […]

Hey
ersteinmal Danke für all die Antworten und Mühen.
Habe das veränderte Programm von Lutz ausprobiert und es funktioniert^^

Allerdings habe ich dabei eine kleine Sache nicht ganz verstanden und würde Sie gerne nocheinmal an einem Beispiel erklärt bekommen:


/* Lese bis Doppelstrich */
while(fgetc(data)!=’"’)putchar(’.’);
/* Lese Zahl mit Nachkommastellen */
fscanf(data,"%lf", Array+i);
/* Lese bis Doppelstrich */
while(fgetc(data)!=’"’)putchar(’,’);
/* Ueberspringe Leer- und Trennzeichen */
do{ c=fgetc(data); } while((c==’ ‚)||(c==‘,’)||(c==’\n’));
ungetc(c,data);


Dieses Programmstück erschließt sich mir noch nicht ganz erschlossen. Wie müsste ich es verändern, wenn ich plötzlich eine CSV Datei einlesen möchte die folgende Codierung hat:

33,9;30,8;25,1;23,7;26,2;27,6;29,5
33,9;30,8;25,1;23,7;26,2;27,6;29,5
33,9;30,8;25,1;23,7;26,2;27,6;29,5
33,9;30,8;25,1;23,7;26,2;27,6;29,5

Also eine die mit , ist und durch Semikolon getrennt wird?
Vieleicht verstehe ich anhand dieses Beispiels dann was oben gemeint ist.

Danke nocheinmal für alles

Liebe Grüße
Alex

Hey
ersteinmal Danke für all die Antworten und Mühen.
Habe das veränderte Programm von Lutz ausprobiert und es funktioniert^^

Allerdings habe ich dabei eine kleine Sache nicht ganz verstanden und würde Sie gerne nocheinmal an einem Beispiel erklärt bekommen:


/* Lese bis Doppelstrich */
while(fgetc(data)!=’"’)putchar(’.’);
/* Lese Zahl mit Nachkommastellen */
fscanf(data,"%lf", Array+i);
/* Lese bis Doppelstrich */
while(fgetc(data)!=’"’)putchar(’,’);
/* Ueberspringe Leer- und Trennzeichen */
do{ c=fgetc(data); } while((c==’ ‚)||(c==‘,’)||(c==’\n’));
ungetc(c,data);


Dieses Programmstück erschließt sich mir noch nicht ganz erschlossen. Wie müsste ich es verändern, wenn ich plötzlich eine CSV Datei einlesen möchte die folgende Codierung hat:

33,9;30,8;25,1;23,7;26,2;27,6;29,5
33,9;30,8;25,1;23,7;26,2;27,6;29,5
33,9;30,8;25,1;23,7;26,2;27,6;29,5
33,9;30,8;25,1;23,7;26,2;27,6;29,5

Also eine die mit , ist und durch Semikolon getrennt wird?
Vieleicht verstehe ich anhand dieses Beispiels dann was oben gemeint ist.

Danke nocheinmal für alles

Liebe Grüße
Alex

Hi,

dann solltest Du Deine Datenquelle so ändern, dass sie einen Dezimalpunkt verwendet. Oder ein Textmodifizierungsprogramm wie sed oder awk verwenden, um die Umwandlung nachträglich automatisiert vorzunehmen.

Natürlich könntest Du auch einen Parser für das veränderte Format schreiben, allerdings wären dann die Nachkommaziffern zeichenweise zu lesen und verarbeiten, damit führende Nullen nicht verloren gehen. Oder jede Zeile wird als String eingelesen, in einem Durchlauf Komma durch Punkt ersetzt und dann die Zahlen aus dem String mit sscanf gelesen.

Wenn keine Anführungszeichen vorhanden sind, dann kann man natürlich das Lesen der Anführungszeichen einfach weglassen.

Gruß Lutz