Zugriff auf Excel-Dateien



  • 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;
    }
    


  • statt %f nimmst du %[^;] oder anstelle des ; das zeichen, was du als separator hast.



  • danke,
    aber was ist ein seperator?

    p.s.: ich möchte nicht nur ein zeichen einlesen, sondern meherer wöreter in einem string



  • separator: trennzeichen in deiner csv datei, das einzelne zellen trennt

    guck dir an, wie scanf funktioniert. dann kapierst du das auch. ich hab jetzt absolut keinen bock, dir das alles haarklein einzutrichtern.


Anmelden zum Antworten