fwrite() und fseek(), bestehende Datei öffnen und an beliebiger Stelle verändern



  • Hallo zusammen!

    Kann mir jemand sagen, wie ich eine Datei oeffne, ohne diese zu zerstoeren, und dann an beliebiger Stelle mit fwrite ein struct in die Datei schreibe? Ich uebersehe irgendetwas, sitzte jetzt schon viel zu lange daran. Im Folgenden finden sich zwei codesnippets mit der jeweils dazugehoerigen Ausgabe in der Konsole. Beide Auszuege sind gleich, lediglich der Modus in dem die Datei geoeffnet wird ist im einen Fall "wb" und im anderen "ab". Das Verhalten von "wb" ist wie erwartet ( Datei wird vor schreiben geleert ), das Verhalten von "ab" dagegen verwundert mich, da das Setzen des Lese/Schreibzeigers offensichtlich keinen Effekt auf fwrite() hat. Guckt mal drueber 😉 Danke

    #include <stdlib.h>
    #include <stdio.h>
    
    #define BILLS_FILE "test.db"
    
    typedef struct {                      
        float total;
        int option1;
    } HEADER;
    
    void write_header( char*, HEADER* );    
    void ppos( char*, FILE* );
    
    int main( int argc, char **argv ) {
    
        HEADER header;
        header.total = 42.23;
        header.option1 = 1000;
    
        write_header( BILLS_FILE, &header );
        return 0;
    }
    
    void write_header( char *file, HEADER *header ){
        FILE *fp;
    
        // MODUS wb... nun sollte von Anfang an alles geaendert werden,
        if(( fp=fopen( file,"wb")) == NULL ){
            perror( file );
            exit(EXIT_FAILURE);
        }
        ppos( "write_header: pos after fopen(): ", fp );
        rewind( fp );
        ppos( "write_header: pos after rewind():", fp );
        fwrite( header, sizeof(HEADER), 1, fp ) ;
        ppos( "write_header: pos after fwrite():", fp );
        printf( "bytes written: %zu\n", sizeof( HEADER ) );
        fclose( fp );
    }
    
    void ppos( char* label, FILE *fp ){ printf( "%s %ld\n", label, ftell( fp ) ); }
    

    Ausgabe:

    $ gcc -std=c99 test.c -o test && ./test
    write_header: pos after fopen():  0
    write_header: pos after rewind(): 0
    write_header: pos after fwrite(): 8
    bytes written: 8
    

    Im folgenden Code ändert sich nun der Dateimodus, ich moechte schliesslich nicht die komplette überschreiben, sondern nur Teile davon. In diesem Beispiel z.B. den ersten Eintrag neu ueberschreiben, der sich an Pos. 0 befindet.

    #include <stdlib.h>
    #include <stdio.h>
    
    #define BILLS_FILE "test.db"
    
    typedef struct {                      
        float total;
        int option1;
    } HEADER;
    
    void write_header( char*, HEADER* );    
    void ppos( char*, FILE* );
    
    int main( int argc, char **argv ) {
    
        HEADER header;
        header.total = 42.23;
        header.option1 = 1000;
    
        write_header( BILLS_FILE, &header );
        return 0;
    }
    
    void write_header( char *file, HEADER *header ){
        FILE *fp;
    
        // MODUS ab... nun sollte die Datei nicht geoeffnet werden, 
        // Der Lese/Schreibzeiger sollte auf das Ende der Datei zeigen.
        // Nach rewind() sollte er auf Anfang gesetzt sein, ein anschliessendes
        // Schreiben mit fwrite() sollte an den Anfang schreiben.
        // Tut es hier aber nicht, warum? 
        if(( fp=fopen( file,"ab")) == NULL ){ 
            perror( file );
            exit(EXIT_FAILURE);
        }
        ppos( "write_header: pos after fopen(): ", fp );
        rewind( fp );
        ppos( "write_header: pos after rewind():", fp );
        fwrite( header, sizeof(HEADER), 1, fp ) ;
        ppos( "write_header: pos after fwrite():", fp );
        printf( "bytes written: %zu\n", sizeof( HEADER ) );
        fclose( fp );
    }
    
    void ppos( char* label, FILE *fp ){ printf( "%s %ld\n", label, ftell( fp ) ); }
    

    Ausgabe

    $ gcc -std=c99 test.c -o test && ./test
    write_header: pos after fopen():  8
    write_header: pos after rewind(): 0
    write_header: pos after fwrite(): 16
    bytes written: 8
    

    Man sieht, trotz rewind(), fwrite() haengt das struct ans Dateiende. Hier, ein
    weiterer, drauffolgender Programmdurchlauf:

    $ ./test 
    write_header: pos after fopen():  24
    write_header: pos after rewind(): 0
    write_header: pos after fwrite(): 32
    bytes written: 8
    


  • "w" steht für schreiben, das löscht wie du erkannt hast die Datei, "a" steht für Anhängen, damit landen alle Schreibvorgänge am Ende der Datei. Was du benötigst ist ein wenig trickreich - du öffnest die Datei zum Lesen (und Schreiben) mit "r+" (bzw. "r+b").



  • Ah vielen Dank!


Anmelden zum Antworten