C Programmieren .csv einlesen und verarbeiten

makke306

Lt. Junior Grade
Registriert
Mai 2010
Beiträge
287
Hallo, ich brauche einen Tipp bei der C Programmierung. Konkret geht es um eine Datei .csv einzulesen und die Daten zu verarbeiten. Die Datei enthält Werte die mit "," getrennt sind. In der letzten Spalte befindet sich eine Temperatur. Ich möchte nun gerne aus all den Daten die Durchschnittstemperatur ermitteln.

Ich habe es hinbekommen die Datei einzulesen. Allerdings scheitere ich nun die Daten zu verarbeiten bzw. die Durchschnittstemperatur zu berechnen. Ich habe dazu in meinem Buch keine Hilfestellung erhalten. So weit ich es sehe müsste ich die Daten in einer While Schleife mit strtok_r trennen und dann den Durchschnitt berechnen.

Kann mir jemand eine kleine Hilfstellung geben? Danke

Code:
#include <stdio.h>
#include <stdlib.h>


char * read_data(char* filename)
{

    int c;
    FILE *datei;

    datei=fopen(filename, "r");
    if(datei != NULL)
    {
        while( (c=fgetc(datei)) != EOF)
            putchar(c);
    }
    else
    {
        printf("Konnte Datei nicht finden bzw. öffnen!\n");
        return EXIT_FAILURE;
    }



}

int main(void)
{

    char* input_data =read_data("data.csv");

    return EXIT_SUCCESS;
}
 

Anhänge

  • data.csv
    5,6 KB · Aufrufe: 135
Zuletzt bearbeitet:
Muss es C sein oder darf es auch C++ sein?

BTW: beim nächsten mal den Code nicht in [icode]-Tags sondern in [code]-Tags packen.
 
Zuletzt bearbeitet:
Ich würde, anstatt per fgetc gleich die komplette Datei einzulesen, mit fgets die Datei Zeile für Zeile bearbeiten, dann sollte es einfacher sein, wie du schon schreibst mit strtok(_r) die Einzelnen Spalten der CSV auszulesen.

Ansonsten kannst du auch den gesamten Dateiinhalt mit strtok durchgehen, dann musst du aber beachten, dass die Werte nicht nur durch ,, sondern auch durch Zeilenwechsel getrennt sind. Du kannst ja mehrere Delimiter übergeben.

Wenn es wirklich nur um den Durchschnitt und nicht um ein Array der einzelnen Werte geht kannst du ja das letzte Token jeder Zeile bzw. in dem spezifischen Falle jedes dritte Token der Datei in einer Variable aufaddieren (den Wert bekommst du ja per atof), und in einer zweiten Variable zählen, wie viele Werte es sind -> teilen für den Mittelwert.
 
  • Gefällt mir
Reaktionen: blöderidiot
@paulinus hat den Weg korrekt vorgegeben. Du müsstest Dir dann nur noch überlegen, auf welche Weise konkret Du die Daten aus der Lesefunktion an das aufrufende Programm übergibst (dynamische Allokation). Du erzeugst entweder ein dynamisches Array double* (wenn nur ein Wert pro Zeile gebraucht wird) oder ein dynamisches Array vom Typ vec3* mit den drei Feldern Pro Zeile: typedef double vec3[3] . Dann musst Du das Array anfangs mit einer großen Zahl möglicher Elemente initialisieren (z.B.: #define MAXDATALENGTH 100000) und beim Einlesen genau mitzählen, wie viele Elemente Du tatsächlich gelesen hast - und diese Zahl mit dem Array an das aufrufende Programm zurückübergeben.

Oder so.


Mit C++ geh das halt viel schöner.
 
So bin nun nach einigen Stunden etwas weiter. Nur funktioniert es nicht.
1. Ich habe mir eine funktion gebastelt inder ich die .csv Datei mit fgets einlese
2. Ich weiß nicht ob das korrekt ist, wie ich es gemacht habe (vermutlich nicht).
3. Ich weiß nicht wie ich es hinbekomme auf der dritten Spalte die Summe zu machen.

Habe versucht ein ähnliches Beispiel im Netzt zu finden, aber ohne Erfolg.

Ich bräuchte eine kleine Hilfe, vielen Dank.

Code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define ZEILENLAENGE 80


char * read_data(char* filename)
{

    FILE *datei;
    char buffer[ZEILENLAENGE];

    datei=fopen(filename,"r");

    if(datei==NULL)
    {
        puts("Ich kann die Datei nicht öffnen!");
        exit(1);
    }

    fgets(buffer,ZEILENLAENGE,datei);

    fclose(datei);

}

int main(void)
{

    char* input_data =read_data("data.csv");
    char * save;
    char * token;


    save = input_data;

    double total_temperature = 0.0f;


    while ((token = strtok_r(save, "\n", &save)))
    {
        char * token1;
        char* save1 = token;
        double temperature = atof(strtok_r(save1, ",", &save1));
        total_temperature += temperature;
    }

    double median = total_temperature/100.0f;

    printf("%f", median);

    return EXIT_SUCCESS;
}
 
makke306 schrieb:
So bin nun nach einigen Stunden etwas weiter. Nur funktioniert es nicht.
1. Ich habe mir eine funktion gebastelt inder ich die .csv Datei mit fgets einlese
2. Ich weiß nicht ob das korrekt ist, wie ich es gemacht habe (vermutlich nicht).
3. Ich weiß nicht wie ich es hinbekomme auf der dritten Spalte die Summe zu machen.

Habe versucht ein ähnliches Beispiel im Netzt zu finden, aber ohne Erfolg.

Ich bräuchte eine kleine Hilfe, vielen Dank.
OK, ich habe Deinen Quelltext leicht umgestellt. Was habe ich geändert:
  • fgets() in read_data() liest nicht nur eine Zeile sondern alle 100
  • main() öffnet/schließt die Datei, ruft read_data() mit dem "filepointer" auf,
  • read_data() liest nur die Datei und sonst nichts, zählt die verarbeiteten Zeilen (*pcount), liefert ein Array mit Werten zurück, in der dritten Spalte ist dann die Temperatur
  • read_data() alloziiert den Datenvektor (hier: 3x double pro Zeile)
  • main() löscht den Datenvektor wieder (das ist zwar nicht schön, aber das Einfachste)
C:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXDATALENGTH 100000 /* so viele Zeilen maximal */
typedef double vec3[3]; /* wir lesen drei Werte pro Zeile */

 vec3* read_data(FILE* fh, int* pcount)
{
 vec3* data = calloc(MAXDATALENGTH, sizeof(vec3));
 char buffer[512], tokens[] = ",;";
 if (data == NULL) return NULL;
 
 while (fgets(buffer, sizeof(buffer), fh)) {
    char* tok = strtok(buffer, tokens);
    int nfield = 0;
    while (tok != NULL)     {
       data[*pcount][nfield++] = atof(tok);
       tok = strtok(NULL, tokens);
    }
    if(nfield) (*pcount)++; /* nfields? -> Datenwert zugefügt -> hochzaehlen */
 }
 
 return data;
}

 int main(void)
{
vec3* temp_data = NULL;
int count = 0;
char filename[] = "data.csv";
FILE *fh = fopen(filename, "r");

 if (fh != NULL) {
    temp_data = read_data(fh, &count); /* 3. Spalte */
    fclose(fh);
 }
 else {
    perror(filename);
 }
 
 if (count) {
    double t_sum = 0, t_mean;
    for (int i = 0; i < count; i++) { // Temp zusammenrechnen
       t_sum += temp_data[i][2];      // field [0], [1],  [2]<-Temp
    }
    t_mean = t_sum / count;
    printf("mean temp of %d measurements: %.2f %cC\n", count, t_mean, (char)248);
 }
 else {
    printf("KEINE DATEN GEFUNDEN\n");
 }
 free(temp_data); // dynamischen Speicher freigeben

 return 0;
}
Allerdings liest Du hier alle drei Spalten für spätere Verarbeitung.

OK, wenn Du wirklich nur den Mittelwert brauchst, reicht eine deutlich kürzere "Minimalversion":
C:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

 int main(void)
{
 double temp_mean = 0;
 int count = 0;
 char filename[] = "data.csv";
 FILE* fh = fopen(filename, "r");

 if (fh != NULL) {
    char buffer[512], tokens[] = ",;";
    double temp_sum = 0;
 
    while (fgets(buffer, sizeof(buffer), fh)) {
       char* tok = strtok(buffer, tokens);
       int nfield = 0;
       while (tok != NULL) {
          if (++nfield == 3) {
             temp_sum += atof(tok);
             count++;
          }
          tok = strtok(NULL, tokens);
       }
    }

    temp_mean = count ? temp_sum / count : 0;
    fclose(fh);
 }
 printf("mean temp of %d lines: %.2f %cC\n", count, temp_mean, (char)248);
 return 0;
}

Anmerkung: in Deinem Beispiel sprichst Du von "double median;", aber um den Median zu berechnen, müsstest Du alle Werte z. B. nach "data"erstmal komplett einlesen, sortieren und dann (bei ungerader Anzahl) das Element genau aus der Mitte des Array heraussuchen. Bei gerader Anzahl (z. B. n=100) nimmst Du dann den Mittelwert der zwei "mittleren" Werte n/2 und (n/2 + 1) aus data. Was Du meinst ist wahrscheinlich double mean;.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: makke306 und BAGZZlash
Danke für die Hilfe. Muss dein Code nochmals genau ansehen um zu sehen ob ich alles verstehe was da passiert.
 
  • Gefällt mir
Reaktionen: kuddlmuddl
Zurück
Oben