Search code examples
cfunctionfile-handling

I can't update new data in the text file


The problem here the code doesn't update the data in the file to the new data,but the code doesn't work. I want to update the file to the new data by the user and display in server side.

This code for update data and I used the buffer to store the data in it.

void bilgi_guncelle()
{
    struct daire d;
    FILE *dosya, *temp;
    int no, bulundu = 0;

    printf("Daire no: ");
    scanf("%d", &no);

    dosya = fopen("aidatlar.txt", "a+");

    if (dosya == NULL)
    {
        printf("Dosya acilamadi\n");
        return;
    }

    temp = fopen("gecici.txt", "w");

    while (fread(&d, sizeof(struct daire), 1, dosya) == 1)
    {
        if (d.no == no)
        {
            bulundu = 1;
            printf("Ad (%s): ", d.ad);
            scanf("%s", d.ad);

            printf("Soyad (%s): ", d.soyad);
            scanf("%s", d.soyad);

            printf("Aidat (%.2f): ", d.aidat);
            scanf("%f", &d.aidat);

            printf("Tarih (%s): ", d.tarih);
            scanf("%s", d.tarih);
        }

        fwrite(&d, sizeof(struct daire), 1, temp);
    }

    fclose(dosya);
    fclose(temp);

    if (!bulundu)
    {
        printf("Daire bulunamadi\n");
        remove("gecici.txt");
        return;
    }

    remove("aidatlar.txt");
    rename("gecici.txt", "aidatlar.txt");

    printf("Bilgi basariyla guncellendi\n");
}

Solution

    1. Incomplete code. I assumed you are using fixed sized strings in your struct daire. If not then you need to allocate those strings before use, typically, by also storing the string length.

    2. No sampledata. write_date() generates test data.

    3. If you are on Windows then the problem is you are not using binary mode when operating on binary data.

    4. Check if fopen("gecici.txt", "w"); is successful.

    5. fopen("...", "a+") sets the file position in an OS-specific fashion per fopen(3):

    For glibc, the initial file position for reading is at the beginning of the file, but for Android/BSD/MacOS, the initial file position for reading is at the end of the file.

    Code below explicitly sets the file position.

    1. Always use a maximum field width when reading strings with scanf().

    2. (Not fixed) Consider registering an exit handler to remove your temporary file if user does ctrl-c mid-stream.

    3. (Not fixed) You currently store no, if they are sequential, maybe don't store it, and just fseek(, no * sizeof(struct daire), SEEK_SET) to get to the record of interest? It means numbers would change if you insert or delete records. This may or may not matter for your use case.

    4. (Not fixed) Consider using SQLite instead of writing your own file format.

    5. (Partially fixed) Use constants instead of magic values (file names).

    This works on Linux:

    #include <stdio.h>
    
    #define AIDATLAR "aidatlar.txt"
    
    #if defined(_WIN32) || defined(WIN32)
    #define BINARY_MODE "b"
    #define F_OK 0
    #include <io.h>
    #else
    #define BINARY_MODE ""
    #include <fcntl.h>
    #include <unistd.h>
    #endif
    
    #define STR_LEN 10
    #define str(s) str2(s)
    #define str2(s) #s
    
    
    struct daire {
        int no;
        char ad[STR_LEN+1];
        char soyad[STR_LEN+1];
        float aidat;
        char tarih[STR_LEN+1];
    };
    
    // write data if file doens't already exist
    void write_data(size_t n, struct daire d[n]) {
        if(!access(AIDATLAR, F_OK)) return;
        FILE *dosya = fopen(AIDATLAR, BINARY_MODE "w");
        if (!dosya) {
            printf("Dosya acilamadi\n");
            return;
        }
        fwrite(d, sizeof *d, n, dosya);
        fclose(dosya);
    }
    
    void bilgi_guncelle() {
        printf("Daire no: ");
        int no;
        scanf("%d", &no);
    
        FILE *dosya = fopen(AIDATLAR, BINARY_MODE "a+");
        if (!dosya) {
            printf("Dosya acilamadi\n");
            return;
        }
        fseek(dosya, 0L, SEEK_SET);
        FILE *temp = fopen("gecici.txt", BINARY_MODE "w");
        if (!temp) {
            printf("Dosya acilamadi\n");
            fclose(dosya);
            return;
        }
        int bulundu = 0;
        struct daire d;
        while (fread(&d, sizeof(struct daire), 1, dosya) == 1) {
            if (d.no == no) {
                bulundu = 1;
                printf("Ad (%s): ", d.ad);
                scanf("%" str(STR_LEN) "s", d.ad);
    
                printf("Soyad (%s): ", d.soyad);
                scanf("%" str(STR_LEN) "s", d.soyad);
    
                printf("Aidat (%.2f): ", d.aidat);
                scanf("%f", &d.aidat);
    
                printf("Tarih (%s): ", d.tarih);
                scanf("%" str(STR_LEN) "s", d.tarih);
            }
            fwrite(&d, sizeof(struct daire), 1, temp);
        }
        fclose(dosya);
        fclose(temp);
        if (!bulundu) {
            printf("Daire bulunamadi\n");
            remove("gecici.txt");
            return;
        }
        remove(AIDATLAR);
        rename("gecici.txt", AIDATLAR);
        printf("Bilgi basariyla guncellendi\n");
    }
    
    int main() {
        struct daire d[] = {
            {0, "a0", "a1", 0.12, "a2"},
            {1, "b0", "b1", 1.12, "b2"},
            {2, "c0", "c1", 2.12, "c2"}
        };
        write_data(sizeof d / sizeof *d, d);
        bilgi_guncelle();
    }
    

    and example session:

    $ ./a.out 
    Daire no: 0
    Ad (a0): a0
    Soyad (a1): a1
    Aidat (0.12): 1.2
    Tarih (a2): a2
    Bilgi basariyla guncellendi
    $ ./a.out 
    Daire no: 0 
    Ad (a0): a0
    Soyad (a1): a1
    Aidat (1.20):