Zugriff auf Excel-Dateien



  • Hallo zusammen,
    ich habe eine Excel-Tabelle die so aussieht:

    Spalte_A    Spalte_B    Spalte_C
    1    1975        2,39        164,454
    2    4562        4,48        193,592
    3    4834        0,79        123,928
    4    2298        9,40        854,467
    

    Ich möchte aus einem AnsiC-Programm mit z.B. dem Wert 2298 (Reihe4, Spalte_A) die dazugehörigen Werte aus Spale B und C "importieren".
    Wie funktioniert so etwaS? Hat jemand ein Beispiel für mich?

    Viele Grüße,
    chemph



  • achso, mit "importieren" meine ich, dass ich z.B. eine Funktion mit dem Wert als Parameter aufrufe und mit Return die beiden anderen zurückbekomme.



  • schau mal nach "blockweise lesen/schreiben" oder "Arrays in Tabellenkalkulation einlesen !!

    z.B.:
    http://www.pronix.de/pronix-794.html
    http://www.pronix.de/pronix-734.html <-- *.CSV



  • @chemph
    Ich kann dir leider nicht helfen.
    So weit ich weiss geht das z.B über sql Abfragen, es gibt sicher auch andere Methoden, aber um es einfach so mit fread auslesen müsste man die Aufbau der Excel-Dateien kennen, und ob das irgendwo frei zugänglich ist kann ich dir nicht sagen.
    Vielleicht wäre es doch am besten die Excel-Tabele erst als csv-Datei ab zu speichern?



  • Marcin schrieb:

    Vielleicht wäre es doch am besten die Excel-Tabele erst als csv-Datei ab zu speichern?

    Ja, das würde auch gehen. Wie funktioniert das dann?



  • "Datei, Speichern unter"
    <Dateiname (test.csv)> oder
    <Dateiname (test) und als Dateityp (*.csv)> 😮



  • @coolzero0001: Das ist mir schin klar, aber wie lese ich die Daten aus meinem Programm? Ich möchte zu dem Wert 2298 die beiden anderen werte lesen.

    so soll's aussehen:

    int lesen(Wert_A)
    {
        was hier stehen soll weiss ich nicht; ;-)
        return Wert_B, Wert_C;
    }
    

    Also: Es muss keine Excel-Datei sein, kann auch *.txt oder was anderes sein und im Programm rufe ich eine Funktion mit dem Wert_A auf, und bekomme als Returnvalue Wert_B und Wert_C. Vergleichbar mit z.B. einer Mitgliederdatenbak eines Vereins. --> Die Mitgliedsnummer ist Parameter für die Funktion und Name, Vorname und so weiter liefert die Funktion zurück.



  • man kann keine zwei werte zurueckgeben



  • Moh schrieb:

    man kann keine zwei werte zurueckgeben

    ok. Dann aber so:

    int lesen(Wert_A)
    {
        was hier stehen soll weiss ich nicht; ;-)
        Hier sollen die Werte A und B in Variablen geschrieben werden;
        return 0;
    }
    

    oder so:

    int lesen_wert_b(Wert_A)
    {
        was hier stehen soll weiss ich nicht; ;-)
        return Wert_B;
    }
    
    int lesen_wert_c(Wert_A)
    {
        was hier stehen soll weiss ich nicht; ;-)
        return Wert_C;
    }
    

    Wie gesagt, es kann auch eine *.txt-Datei oder so etwas sein...



  • du kannst structs zurueckgeben. probier das mal.



  • ja, aber ich muss doch erstmal irgendeine datei haben, aus der ich etwas lesen kann. Die datei kann auch von einem anderen Programm erstellt werden. Das könnte so aussehen:

    datensatz_anlegen(Name, Vorname, Nummer);
    

    Dann soll das Programm irgendwie diese Daten in eine Datei speichern.

    diese Werte möchte ich mir dann mit so einer Funktion wiederholen:

    int lesen_wert_b(Wert_A)
    {
        was hier stehen soll weiss ich nicht; ;-)
        return Wert_B;
    }
    
    int lesen_wert_c(Wert_A)
    {
        was hier stehen soll weiss ich nicht; ;-)
        return Wert_C;
    }
    


  • zeilenweise einlesen mit fgets
    zeilen mit sscanf zerlegen
    erhaltene werte in ein struct packen
    struct in den speicher packen (malloc, realloc, free,...)

    sscanf(zeile, "%s\t%s\t%s\t%s", str1, str2, str3, str4);
    die einzelnen zellenwerte duerfen so aber keine leerzeichen enthalten.
    wenn doch, frag nochmal, denn da gibts noch weitere moeglichkeiten.



  • zeilenweise einlesen mit fgets
    zeilen mit sscanf zerlegen
    erhaltene werte in ein struct packen
    struct in den speicher packen (malloc, realloc, free,...)

    danke, aber das da oben sagt mir ehrlich gesagt noch nicht so viel.
    Ich habe das jetzt so verstanden:

    sscanf(zeile, "%s\t%s\t%s\t%s", str1, str2, str3, str4);
    

    liest 4 strings aus einer textdatei mit tabulator getrennten werten. Ich müsste dann sscanf so lange aus einer schleife ausführen, bis mein gewünschter Wert im ersten String stehe. Dann kann ich mir den rest "reinsaugen", richtig? Und ich nehme an, dass das auch mit integer oder double geht?...?



  • Hier ist meine Version:

    #include <stdio.h> 
    #include <stdbool.h>
    
    int readrow(FILE *fp,int column_a, double *column_b, double *column_c)
    {
        int i,c,rc;
        bool found;
    
        /*Erste zeile ueberlesen*/
        c = fgetc(fp);
        while(c!='\n' && c !=EOF)
        c = fgetc(fp);
    
        rc = 0;
        found = false;
        while(!found && c!=EOF)
        {	
            /*Zeilennummer ueberspringen*/
            c = fgetc(fp);
            while(c!=';' && c !=EOF)
                c = fgetc(fp);	
            /*Wert aus Spalte A einlesen*/
            fscanf(fp,"%d",&i);
            /*Wert aus Spalte A mit a vergleichen*/
            if(i != column_a)
            {
                /*fals nicht gleich zur naechten Zeile Springen*/
                c = fgetc(fp);
                while(c!='\n' && c !=EOF)
                c = fgetc(fp);
            }
            else
            {	
                rc = 1;
                /*falls doch beiden anderen werte einlesen;*/		
                fgetc(fp); /*;-lesen*/
                rc += fscanf(fp, "%lf", column_b);
                fgetc(fp); /*;-lesen*/
                rc += fscanf(fp, "%lf", column_c);
                found = true;
            }
        }
        return rc;
    }
    

    Und Testprogramm:

    #include <stdio.h> 
    #include <locale.h>
    
    int main( ) 
    {
        int rc; 
        FILE *fp; 
        double b, c; 
    
        setlocale(LC_NUMERIC,"");
    
        fp = fopen("tabele.csv","rb"); 
        if((rc = readrow(fp, 4562, &b, &c)) == 3)
    	printf("Alles eingelesen:%d\n",rc);
        else
    	printf("Nicht alles eingelesen:%d\n",rc);
    
        printf("SPALTE  A:%d   B:%.2f  C:%.2f\n",4562,b,c);
    
        fclose(fp);
    
        return 0;
    }
    

    Trennzeichen in der csv-Datei ist ';'
    Die csv-Datei muss also etwa so aussehen:

    ;Spalte_A;Spalte_B;Spalte_C;
    1;1975;2,39;164,454;
    2;4562;623,3;3244,1;
    3;4834;0,79;123,928;
    4;2298;9,40;854,467;
    


  • eine datei ist eine reihe von bytes. du kannst da zwar drin rumspringen, aber nicht zeilenweise.

    du musst schon zeilenweise lesen, und das kannst du auch nur, wenn du weisst was eine zeile ist (naemlich das, was fgets zurueckgibt).

    erst wenn du aus ner "reihe von bytes" einen haufen "zeilen" gemacht hast, kannst du aus einer "zeile" eine "reihe von strings" machen.

    und wenn du eine "reihe von strings" hast, kannst du daraus etwas bedeutungsvolles wie "ID, jahreszahl, reelle_zahl_1, reelle_zahl_2" samt dazugehoerigen typen (int, int, float, float) machen.

    und JETZT kannst du auch auf diesen haufen *information* filtern, denn das konntest du auf diesen undurchsichtigen haufen genannt "reihe von bytes" noch nicht.

    du hast den eindruck gemacht diese hinweise zu brauchen. deswegen schreib ich das.

    edit:
    und jetzt mal was "angewandtes"...

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define LINELEN 1024
    
    struct line_t {
    	int index;
    	int col1;
    	double col2;
    	double col3;
    };
    
    void strsub(char *subj, char search, char replace)
    {
    	for(; *subj; ++subj)
    		if (*subj == search)
    			*subj = replace;
    }
    
    int parseline(char *szline, struct line_t *to)
    {
    	strsub(szline, ',', '.'); // 123.456, not 123,456!
    	return 4 != sscanf(szline, "%d;%d;%lf;%lf", &to->index, &to->col1, &to->col2, &to->col3); // returns success
    }
    
    int addline(struct line_t *pline, struct line_t **palines, int *pnlines)
    {
    	int ntemp = *pnlines + 1;
    	struct line_t *atemp;
    
    	if (!(atemp = realloc(*palines, sizeof(struct line_t) * ntemp)))
    		return 1;
    
    	*palines = atemp;
    
    	memcpy(&atemp[ntemp-1], pline, sizeof(struct line_t));
    
    	*pnlines = ntemp;
    
    	return 0;
    }
    
    int find(struct line_t *alines, int nlines, int start, int filter(struct line_t *))
    {
    	int i;
    
    	for (i = start; i < nlines; ++i)
    		if (filter(&alines[i]))
    			return i;
    
    	return -1;
    }
    
    int filter_col1_4562(struct line_t *line)
    {
    	return (line->col1 == 4562);
    }
    
    int main(int argc, char **argv)
    {
    	FILE *f;
    	char buffer[LINELEN];
    	struct line_t line;
    	int nlines = 0, i;
    	struct line_t *alines = NULL;
    
    	if (argc < 2)
    		return puts("no file specified!"), 0;
    
    	if (!(f = fopen(argv[1], "r")))
    		return puts("file not found!"), 0;
    
    	for (i = 0, nlines = 0; !ferror(f) && !feof(f); ++i)
    	{
    		if (!fgets(buffer, LINELEN, f))
    			break;
    
    		if (parseline(buffer, &line))
    		{
    			i -= 1; // roll back
    			continue;
    		}
    
    		printf("%-3d: %5d\t%5d\t%8g\t%8g\n", i, line.index, line.col1, line.col2, line.col3);
    
    		if (addline(&line, &alines, &nlines))
    			break;
    	}
    
    	puts("\nfiltering for 4562 in \"col1\"...");
    
    	for (i = 0; i < nlines; ++i)
    	{
    		i = find(alines, nlines, i, filter_col1_4562);
    
    		if (i == -1)
    			break;
    
    		printf("record %d is [%5d; %5d; %8lg; %8lg]\n", i, alines[i].index, alines[i].col1, alines[i].col2, alines[i].col3);
    	}
    
    	free(alines);
    
    	fclose(f);
    
    	return 0;
    }
    

    und so sieht die datei aus

    ;Spalte_A;Spalte_B;Spalte_C
    booga booga!!
    1;1975;2,39;164,454
    2;4562;623,3;3244,1
    3;4834;0,79;123,928
    4;4562;3.1415; 2.7182
    5;2298;9,40;854,467
    

    und das ist die ausgabe:

    0  :     1       1975       2.39         164.454
    1  :     2       4562      623.3          3244.1
    2  :     3       4834       0.79         123.928
    3  :     4       4562     3.1415          2.7182
    4  :     5       2298        9.4         854.467
    
    filtering for 4562 in "col1"...
    record 1 is [    2;  4562;    623.3;   3244.1]
    record 3 is [    4;  4562;   3.1415;   2.7182]
    

    codekommentierung auf anfrage
    mehr edits gibts selbstverstaendlich kostenlos 😉



  • Du kannst doch auch den Lesezeiger positionieren:
    fsetpos, fgetpos und fseek, ftell 💡

    /* fpos.c */
    #include <stdio.h>
    #include <stdlib.h>
    #define ZEICHENLAENGE 20
    
    int main(void) {
       FILE *quelle;
       char zeile[ZEILENLAENGE];
       char datei[20];
       fpos_t pos;
    
       printf("Welche Datei wollen Sie Öffnen : ");
       scanf("%s",datei);
    
       if( (quelle=fopen(datei,"r")) == NULL) {
          fprintf(stderr, "\nKonnte %s nicht oeffnen!!\n", datei);
          return EXIT_FAILURE;
       }
       /* Wir lesen die aktuelle Position unseres FILE-Zeigers */
       fgetpos(quelle,&pos);
       printf("\nDer Positionszeiger zeigt auf Byte : %ld\n\n",pos);
    
          while(fgets(zeile, ZEILENLAENGE, quelle))
          fputs(zeile, stdout);
    
       printf("\nGroesse der Datei= Byte : %ld\n", ftell(quelle));
    
       /* Wir setzen den FILE-Zeiger wieder zum Anfang der Datei */
       fsetpos(quelle,&pos);
       printf("Wir sind wieder an Position %ld\n",pos);
    
       system("PAUSE"); return EXIT_SUCCESS;
    }
    


  • c.rackwitz schrieb:

    du kannst da zwar drin rumspringen, aber nicht zeilenweise.

    coolzero0001 schrieb:

    Du kannst doch auch den Lesezeiger positionieren

    und das bringt dir hier genau garnichts.



  • Hallo nochmal,
    so, wie der Code unten von Marcin steht, funktioniert er. Auch, wenn ich anstelle von doubles integer einlese. Probleme gibt es allerdings bei strings.
    Wie geht das genau? Muss ich z.B. char text[20] einlesen? und schreibe ich dann %c oder %s? Ich habe verschiedenes ausprobiert, bekomme aber entweder nur einen Buchstaben wieder oder irgendein undefinierten zeichensatz.....

    Marcin schrieb:

    Hier ist meine Version:

    #include <stdio.h> 
    #include <stdbool.h>
    
    int readrow(FILE *fp,int column_a, double *column_b, double *column_c)
    {
        int i,c,rc;
        bool found;
    	
        /*Erste zeile ueberlesen*/
        c = fgetc(fp);
        while(c!='\n' && c !=EOF)
        c = fgetc(fp);
    
        rc = 0;
        found = false;
        while(!found && c!=EOF)
        {	
            /*Zeilennummer ueberspringen*/
            c = fgetc(fp);
            while(c!=';' && c !=EOF)
                c = fgetc(fp);	
            /*Wert aus Spalte A einlesen*/
            fscanf(fp,"%d",&i);
            /*Wert aus Spalte A mit a vergleichen*/
            if(i != column_a)
            {
                /*fals nicht gleich zur naechten Zeile Springen*/
                c = fgetc(fp);
                while(c!='\n' && c !=EOF)
                c = fgetc(fp);
            }
            else
            {	
                rc = 1;
                /*falls doch beiden anderen werte einlesen;*/		
                fgetc(fp); /*;-lesen*/
                rc += fscanf(fp, "%lf", column_b);
                fgetc(fp); /*;-lesen*/
                rc += fscanf(fp, "%lf", column_c);
                found = true;
            }
        }
        return rc;
    }
    

    Und Testprogramm:

    #include <stdio.h> 
    #include <locale.h>
    
    int main( ) 
    {
        int rc; 
        FILE *fp; 
        double b, c; 
    	
        setlocale(LC_NUMERIC,"");
    	 
        fp = fopen("tabele.csv","rb"); 
        if((rc = readrow(fp, 4562, &b, &c)) == 3)
    	printf("Alles eingelesen:%d\n",rc);
        else
    	printf("Nicht alles eingelesen:%d\n",rc);
    	
        printf("SPALTE  A:%d   B:%.2f  C:%.2f\n",4562,b,c);
    	
        fclose(fp);
    
        return 0;
    }
    

    Trennzeichen in der csv-Datei ist ';'
    Die csv-Datei muss also etwa so aussehen:

    ;Spalte_A;Spalte_B;Spalte_C;
    1;1975;2,39;164,454;
    2;4562;623,3;3244,1;
    3;4834;0,79;123,928;
    4;2298;9,40;854,467;
    


  • char bar[20];
    sscanf("abc foo xyz", "abc %s xyz", bar);



  • c.rackwitz schrieb:

    char bar[20];
    sscanf("abc foo xyz", "abc %s xyz", bar);

    ja...
    ähnlichte zeichenketten habe ich auch schon probiert. aber ich brauche die strings im oberen code...

    Marcin hat folgende codes reingestellt.
    Ich habe mal fett markiert, was irgendwie geändert werden muss. wie gesagt, mit integern funktioniert es ja wunderbar...

    #include <stdio.h>
    #include <stdbool.h>
    
    int readrow(FILE *fp,int column_a, [b]double *column_b[/b], double *column_c)
    {
        int i,c,rc;
        bool found;
    
        /*Erste zeile ueberlesen*/
        c = fgetc(fp);
        while(c!='\n' && c !=EOF)
        c = fgetc(fp);
    
        rc = 0;
        found = false;
        while(!found && c!=EOF)
        {   
            /*Zeilennummer ueberspringen*/
            c = fgetc(fp);
            while(c!=';' && c !=EOF)
                c = fgetc(fp);   
            /*Wert aus Spalte A einlesen*/
            fscanf(fp,"%d",&i);
            /*Wert aus Spalte A mit a vergleichen*/
            if(i != column_a)
            {
                /*fals nicht gleich zur naechten Zeile Springen*/
                c = fgetc(fp);
                while(c!='\n' && c !=EOF)
                c = fgetc(fp);
            }
            else
            {   
                rc = 1;
                /*falls doch beiden anderen werte einlesen;*/       
                fgetc(fp); /*;-lesen*/
                [b]rc += fscanf(fp, "%lf", column_b);[/b]
                fgetc(fp); /*;-lesen*/
                rc += fscanf(fp, "%lf", column_c);
                found = true;
            }
        }
        return rc;
    }
    
    #include <stdio.h>
    #include <locale.h>
    
    int main( )
    {
        int rc;
        FILE *fp;
        [b]double b[/b], c;
    
        setlocale(LC_NUMERIC,"");
    
        fp = fopen("tabele.csv","rb");
        if((rc = readrow(fp, 4562, &b, &c)) == 3)
        printf("Alles eingelesen:%d\n",rc);
        else
        printf("Nicht alles eingelesen:%d\n",rc);
    
        printf("SPALTE  A:%d   [b]B:%.2f[/b]  C:%.2f\n",4562,b,c);
    
        fclose(fp);
    
        return 0;
    }
    

Log in to reply