Problem beim Datei auslesen



  • Hallo, ich versuche gerade eine Datei auszulesen.
    Der Dateiinhalt sieht so aus: ABCD

    Allerdings wird mir folgendes ausgegeben: ABCD`Ft
    Irgendwie werden da zu viele Zeichen ausgegeben.
    Hat wer eine Ahnung was ich da falsch mache?

    #include <stdlib.h>
    
    long GetSizeOfFile(char *Filename)
    {
        FILE *inptr = fopen(Filename, "r");
        fseek (inptr, 0, SEEK_END);
        long FileSize =ftell (inptr);
        fclose (inptr);
        return FileSize;
    }
    
    int main(int argc, char *argv[])
    {
        long Filesize;
        Filesize = GetSizeOfFile("file.txt");
        printf("File size: %d\n", Filesize);
    
        char * buf = malloc(Filesize+1 * sizeof(char));
        printf("size of buf: %d\n", sizeof(buf));
    
        FILE *inptr = fopen("file.txt", "r");
        fread(&buf, Filesize, 1, inptr);
    
        printf("buf: %s\n",&buf);
    
        free(buf);
        fclose(inptr);
        getch();
    
        return 0;
    }
    


  • Du reservierst zwar ein Byte für die abschließende 0, besetzt das letzte Element im Puffer aber nicht mit 0. printf liest dann fröhlich über das Pufferende bis es irgendwann eine 0 findet.



  • Du hast mehrere Fehler:
    Der printf-Formatspecifier für long ist u.a. %ld

    Der Inhalt vom Zeiger buf zeigt schon auf den Speicher, den du mit malloc besorgt hast.
    &buf gibt die Adresse vom Zeiger selber.
    Lass den Adressoperotor & weg.

    printf gibt bei %s solange Zeichen aus, bis eine 0 (Null, '\0') kommt. Diese ist aber nicht abgespeichert.
    Kannst du selber machen oder fgets benutzen.



  • OT:
    sizeof(char) ist immer 1
    sizeof(buf) liefert die die Größe von char* und nicht die des mit malloc angeforderten Speichers.



  • Danke jetzt funktioniert es.
    Allerdings wundert mich das man Filesize+1 schreiben soll bei der malloc Funktion:malloc(Filesize +1 * sizeof(char));

    Meine Datei ist 4 Zeichen groß. Daher hat ja auch die Variable :Filesize: den Wert 4.
    Dann hänge ich weiter unten ja einen Nullterminator an den String an: :buf[Filesize]='\x00';:
    Da Filesize hier ja jetzt den Wert 4 hat schreibe ich an die 5ten Position vom String den Nullterminator. (Im Array zählt man ja von 0)

    ABCD@ ( @ = Nullterminator )
    01234

    Daher frage ich mich gerade warum man Filesize+1 schreiben soll.

    #include <stdio.h>
    #include <stdlib.h>
    
    long GetSizeOfFile(char *Filename)
    {
        FILE *inptr = fopen(Filename, "r");
        fseek (inptr, 0, SEEK_END);
        long FileSize =ftell (inptr);
        fclose (inptr);
        return FileSize;
    }
    
    int main(int argc, char *argv[])
    {
        long Filesize = GetSizeOfFile("file.txt");
        printf("File size: %ld\n", Filesize);
    
        char * buf = malloc(Filesize * sizeof(char));
        FILE *inptr = fopen("file.txt", "r");
        fread(buf, Filesize, 1, inptr);
    
        buf[Filesize] = '\x00';
        printf("buf: %s\n",buf);
    
        free(buf);
        fclose(inptr);
        getch();
    
        return 0;
    }
    


  • @bassmaster sagte in Problem beim Datei auslesen:

    schreibe ich an die 5ten Position vom String

    Und wo kommt die 5. Position her, wenn du nicht +1 anforderst?



  • Bei malloc wird die Größe angegeben.
    Ebenso wird bei der Definition von Arrays die Anzahl der Elemente angegeben.

    Da der Index immer bei 0 anfängt, ist der größte zulässige Index eben Größe-1 bzw. Anzahl-1

    Die Definition ist etwas anderes als der Zugriff.



  • @bassmaster sagte in Problem beim Datei auslesen:

    char * buf = malloc(Filesize+1 * sizeof(char));

    Es gilt auch hier Punkt vor Strichrechnung.
    Da sizeof(char)immer 1 ist, kommt hier zufällig das richtige Ergebnis raus.



  • @dirkb sagte in Problem beim Datei auslesen:

    @bassmaster sagte in Problem beim Datei auslesen:

    char * buf = malloc(Filesize+1 * sizeof(char));

    Es gilt auch hier Punkt vor Strichrechnung.
    Da sizeof(char)immer 1 ist, kommt hier zufällig das richtige Ergebnis raus.

    Ja, das hatte ich schon in einem Lernvideo gesehen. Ich hatte es jetzt einfach so übernommen.

    Dann poste ich hier nochmal den korrekten Code vielleicht können andere Leute damit auch noch etwas anfangen.

    #include <stdio.h>
    #include <stdlib.h>
    
    long GetSizeOfFile(char *Filename)
    {
        FILE *inptr = fopen(Filename, "r");
        fseek (inptr, 0, SEEK_END);
        long FileSize =ftell (inptr);
        fclose (inptr);
        return FileSize;
    }
    
    int main(int argc, char *argv[])
    {
        long Filesize = GetSizeOfFile("file.txt");
        printf("File size: %ld\n", Filesize);
    
        char * buf = malloc(Filesize + 1);
        FILE *inptr = fopen("file.txt", "r");
        fread(buf, Filesize, 1, inptr);
    
        buf[Filesize] = '\x00';
        printf("buf: %s\n",buf);
    
        free(buf);
        fclose(inptr);
        getch();
    
        return 0;
    }
    


  • du solltest dir aber angewöhnen

    char * buf = malloc((Filesize + 1) * sizeof(char));

    zu schreiben. außerdem funktioniert ftell nur für dateien bis 2GB, auch das solltest du beachten. als alternativen gibt es für windows _ftelli64 und unter unix stat64.



  • @wade1234 sagte in Problem beim Datei auslesen:

    du solltest dir aber angewöhnen

    char * buf = malloc((Filesize + 1) * sizeof(char));

    zu schreiben.

    Warum, wenn sizeof(char) immer 1 ist.

    Oh ja, man könnte buf ja auch auf einen anderen Datentyp zeigen lassen.

    Dann macht man aber
    char * buf = malloc((Filesize + 1) * sizeof(*buf));



  • stürzt das programm nicht ab, wenn buf zufällig gleich NULL ist?



  • @wade1234 sagte in Problem beim Datei auslesen:

    stürzt das programm nicht ab, wenn buf zufällig gleich NULL ist?

    Nein.
    buf wird bei sizeof nicht dereferenziert.



  • Ich möchte noch was anderes kritisieren: ich finde das Pattern "Datei öffnen - Größe lesen - Datei schließen - Datei öffnen - Inhalt lesen" nicht gut, da hier die Datei einmal unnötig geschlossen und wieder neu geöffnet wird. Die nächste Frage ist sowieso, warum man immer gleich einen Puffer der Dateilänge allocen will. Was, wenn die Datei größer ist als der RAM? Das erscheint mir - zumindest im allgemeinen Fall - etwas gewagt.



  • @bassmaster sagte in Problem beim Datei auslesen:

        fseek (inptr, 0, SEEK_END);
        long FileSize =ftell (inptr);
    

    Ergibt die Anzahl der Bytes im Stream inptr. Sollte in der Datei EOL als \r\n statt bloß \n auftauchen stimmt diese Zahl nicht mit der Anzahl der Zeichen überein, die im Textmodus von fread() gelesen werden.

    @bassmaster sagte in Problem beim Datei auslesen:

    long Filesize = GetSizeOfFile("file.txt");
    char * buf = malloc(Filesize + 1);
    FILE *inptr = fopen("file.txt", "r");
    fread(buf, Filesize, 1, inptr);
    
    buf[Filesize] = '\x00';
    printf("buf: %s\n",buf);
    

    Gibt also in diesem Fall am Ende EOL Zeichen lang quatsch aus. Besser:

    size_t bytes_read = fread(buf, 1, Filesize, inptr);
    buf[bytes_read] = '\0';
    

    oder calloc() statt malloc().



  • @swordfish sagte in Problem beim Datei auslesen:

    @bassmaster sagte in Problem beim Datei auslesen:

        fseek (inptr, 0, SEEK_END);
        long FileSize =ftell (inptr);
    

    Ergibt die Anzahl der Bytes im Stream inptr. Sollte in der Datei EOL als \r\n statt bloß \n auftauchen stimmt diese Zahl nicht mit der Anzahl der Zeichen überein, die im Textmodus von fread() gelesen werden.

    @bassmaster sagte in Problem beim Datei auslesen:

    long Filesize = GetSizeOfFile("file.txt");
    char * buf = malloc(Filesize + 1);
    FILE *inptr = fopen("file.txt", "r");
    fread(buf, Filesize, 1, inptr);
    
    buf[Filesize] = '\x00';
    printf("buf: %s\n",buf);
    

    Gibt also in diesem Fall am Ende EOL Zeichen lang quatsch aus. Besser:

    size_t bytes_read = fread(buf, Filesize, 1, inptr);
    buf[bytes_read] = '\0';
    

    oder calloc() statt malloc().

    Ja, das Problem mit dem Zeilenumbruch habe ich auch gerade bekommen als ich mehrere Zeilen in meiner Datei hatte:

    Dateiinhalt:
    ABCD
    EFGH

    size_t bytes_read = fread(buf, Filesize, 1, inptr);
    

    bytes_read gibt mir aber komischerweise immer nur 0 als Rückgabewert aus aber in meiner Datei stehen doch mehr als nur 0 Zeichen.

    Hier ist der Code mit malloc:

    #include <stdio.h>
    #include <stdlib.h>
    
    long GetSizeOfFile(char *Filename)
    {
        FILE *inptr = fopen(Filename, "r");
        fseek (inptr, 0, SEEK_END);
        long FileSize =ftell (inptr);
        fclose (inptr);
        return FileSize;
    }
    
    int main(int argc, char *argv[])
    {
        long Filesize = GetSizeOfFile("file.txt");
        printf("File size: %ld\n", Filesize);
    
        char * buf = malloc(Filesize+1);
        FILE *inptr = fopen("file.txt", "r");
    
        size_t bytes_read = fread(buf, Filesize, 1, inptr);
        printf("bytes_read: %d\n",bytes_read);
    
        buf[Filesize] = '\x00';
        printf("buf: %s\n",buf);
    
        free(buf);
        fclose(inptr);
        getch();
    
        return 0;
    }
    

    Wenn ich allerdings calloc verwende dann funktioniert alles ohne Probleme.

    #include <stdio.h>
    #include <stdlib.h>
    
    long GetSizeOfFile(char *Filename)
    {
        FILE *inptr = fopen(Filename, "r");
        fseek (inptr, 0, SEEK_END);
        long FileSize =ftell (inptr);
        fclose (inptr);
        return FileSize;
    }
    
    int main(int argc, char *argv[])
    {
        long Filesize = GetSizeOfFile("file.txt");
        printf("File size: %ld\n", Filesize);
    
        char * buf = calloc(Filesize+1,1);
        FILE *inptr = fopen("file.txt", "r");
    
        size_t bytes_read = fread(buf, Filesize, 1, inptr);
        printf("bytes_read: %d\n",bytes_read);
    
        printf("buf: %s\n",buf);
    
        free(buf);
        fclose(inptr);
        getch();
    
        return 0;
    }
    
    


  • Du gehst davon aus, dass die Größe der Datei mit der Anzahl der gelesenen Zeichen in Deinen Buffer gleich ist.
    Das ist aber eine falsche Annahme, zumindest auf einem Windows PC.

    Du öffnest die Datei im Textmode. Die Datei enthält CR/LF Seqeunzen, die aber ein ein einzelnes LF.

    Oben fragst Du die Datei Größe ab, die auch CRs mitzählst.
    Unten führst Du fread aus, und bekommst auch bytes_read.

    Mit

    buf[Filesize] = '\x00';
    

    solltes es gehen.

    Swordfisch hatte das aber auch schon geschrieben!



  • @bassmaster sagte in Problem beim Datei auslesen:

    bytes_read gibt mir aber komischerweise immer nur 0 als Rückgabewert aus

    Das kann am falschen Formatspecifier liegen. Der muss zu dem Typ passen, den du an printf übergibst.

    size_t bytes_read = fread(buf, Filesize, 1, inptr);
    printf("bytes_read: %d\n",bytes_read);

    Der richtige Formatspecifier für den Typ size_t ist u.a %zd

    Auf welchem System (CPU-Architektur, Betriebssystem, Compiler) programmierst du?



  • @bassmaster sagte in Problem beim Datei auslesen:

    size_t bytes_read = fread(buf, Filesize, 1, inptr);
    

    bytes_read gibt mir aber komischerweise immer nur 0 als Rückgabewert aus aber in meiner Datei stehen doch mehr als nur 0 Zeichen.

    Ja, sorry, hab ich übersehen. fread() gibt die Anzahl der vollständig gelesen Objekte zurück - oben also Filesize-lange Blöcke aus unsigned char. Da aber bei vorhandenen Zeilenumbrüchen der Form \r\n nichteinmal 1 Filesize langer Block gelesen werden kann, gibt fread() so wie oben benutzt 0 zurück.

    Besser also 1 unsigned char lange Blöcke lesen, Filesize mal:

    size_t bytes_read = fread(buf, 1, Filesize, inptr);



  • @dirkb sagte in Problem beim Datei auslesen:

    Auf welchem System (CPU-Architektur, Betriebssystem, Compiler) programmierst du?

    Windows 10 x64
    \CodeBlocks\MinGW\bin>gcc --version
    gcc (tdm-1) 4.7.1

    @swordfish sagte in Problem beim Datei auslesen:

    @bassmaster sagte in Problem beim Datei auslesen:

    size_t bytes_read = fread(buf, Filesize, 1, inptr);
    

    bytes_read gibt mir aber komischerweise immer nur 0 als Rückgabewert aus aber in meiner Datei stehen doch mehr als nur 0 Zeichen.

    Ja, sorry, hab ich übersehen. fread() gibt die Anzahl der vollständig gelesen Objekte zurück - oben also Filesize-lange Blöcke aus unsigned char. Da aber bei vorhandenen Zeilenumbrüchen der Form \r\n nichteinmal 1 Filesize langer Block gelesen werden kann, gibt fread() so wie oben benutzt 0 zurück.

    Besser also 1 unsigned char lange Blöcke lesen, Filesize mal:

    size_t bytes_read = fread(buf, 1, Filesize, inptr);

    Mit unsigned char* funktioniert es jetzt.
    Wenn ich jedoch einen Zeilenumbruch in meiner Datei habe dann werden mir 2 Bytes mehr ausgegeben. Wird da der das \n und der Nullterminator dann mit gerechnet?