Problem beim Datei auslesen



  • @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?



  • @bassmaster sagte in Problem beim Datei auslesen:

    Mit unsigned char* funktioniert es jetzt.

    Darauf wollte ich nicht hinaus. Es ist nur so, daß fread() intern den gegebenen Buffer als unsigned char* interpretiert. Nicht mehr und nicht weniger. Übergeben kannst Du fast alles, was Dir lustig ist.

    @bassmaster sagte in Problem beim Datei auslesen:

    Wenn ich jedoch einen Zeilenumbruch in meiner Datei habe dann werden mir 2 Bytes mehr ausgegeben.

    Zeig Code.



  • @bassmaster sagte in Problem beim Datei auslesen:

    Wenn ich jedoch einen Zeilenumbruch in meiner Datei habe dann werden mir 2 Bytes mehr ausgegeben

    Unter Windows besteht der Zeilenumbruch aus zwei Zeichen
    '\r' für carriage return (Wagenrücklauf) und
    '\n' für new line (Zeilenvorschub)

    Die werden vom System, beim lesen im Textmodus, zu einem einzelnen '\n' gewandelt.

    Bei der Ausgabe sind diese Zeichen nur durch ihre Wirkung zu sehen.
    Wenn du bei printf("buf: <%s>\n",buf); z.B folgende Ausgabe bekommst:

    <ABCD
    >
    

    Dann ist hinter dem D ein \n

    Den Textmodus bekommst du beim fopen mit dem Modus "r".
    Mit "rb" bekommst du den binary-Modus. Da erfolgt keine Wandlung der Steuerzeichen.