Search code examples
cfilebinaryfiles

How to delete records from a relative binary file?


I am thinking about manually deleting records which have grades[5] under 5.I haven' t tried anything yet, because I don' t know where to start.I don't want a function that does the job quick, I want to implement myself a function and understand it, but I don't know how to delete records in relative files. My code should work like this:- the binary file should receive data from the text file and show the searched student, if the student doesn't exists I should add it . After all of this I should be able to delete students that have grade[5] strictly under 5. It is just the deletion function that is missing from my code.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <conio.h>

typedef struct {
    int nrm;             //enrolment number - works as relative key
    char CNP[14];        //string ASCIIZ
    char nume[30];       //string
    int an;              //study year
    int grupa;           //group
    unsigned char note[20];  //grades
    char is;//this is status indicator
} STUDENT;

int filesize(FILE* f, int rec_size)
{//from the crt.pos substract one and i ll know the record of...
    long crt_pos;
    int size;
    //below compute the size of the file in records, withouth altering the crt.pozition
    crt_pos = ftell(f);//save the current pozition in a var, before going to the end of the file
    fseek(f, 0, SEEK_END);//go to the end of the file
    size = ftell(f) / rec_size;//ftell gives the current position and the dim of the record
    fseek(f, crt_pos, SEEK_SET);//ne readuce la positia curenta, initiala pe care am salvat o n var
    return size;
}

void main()
{
    char numefr[30] = "..\\Studenti_r_f.dat";//why \\? changes the meaning of the foll char; afiseaza un singur
    FILE* f;
    STUDENT x;//record variable
    int i, key, dim;//key=key for the record;dim=size of file in records
    //dim changes when computing the sizeof(file), at every iteration
    fopen_s(&f, numefr, "wb+");
    //optionally preform the file

    freopen("..\\input.txt", "rt", stdin);  //remove if reading data from keyboard and uncomment the printf lines

    //printf("Enrollment number: ");
    scanf_s("%d", &key);//read the first field, always the 1 field is the key
    while (!feof(stdin))//process the key read another and so on
    {
        //check key range
        dim = filesize(f, sizeof(STUDENT));//dim=nr de studenti din fisier;nr de recorduri;
        //check the poz indicated by the key, it may have changed since the last iteration
        if (key >= dim)//if the key=10, position 10 doesn t exist
        { //extend the file
            x.is = 0;
            fseek(f, 0, SEEK_END);//go to the end of file and write this record
            for (i = 0; i < key - dim; i++)
                fwrite(&x, sizeof(STUDENT), 1, f);
        }
        fseek(f, key * sizeof(STUDENT), SEEK_SET);//change the pos in the file, go to the pos indicated by the key
        fread(&x, sizeof(STUDENT), 1, f);//read rec from file
        if (x.is == 1)//if is=1, the position is taken, it must always be 0
            printf("\nError: duplicate key %d. Skipping.", key);//read rest of field for student, write record from file then
        else
        {
            x.nrm = key;
            //printf_s("Name: ");
            gets_s(x.nume);
            gets_s(x.nume);
            //printf_s("CNP: ");
            gets_s(x.CNP);
            //printf_s("Year: "); 
            scanf_s("%d", &x.an);
            //printf_s("Group: ");
            scanf_s("%d", &x.grupa);
            for (i = 0; i < 20; i++)
                //x.note[i]=0;
                scanf_s("%d", &x.note[i]);
            x.is = 1;
            //the cur poz is after this record before we write the fseek, which brings us to the beginning of this record
            fseek(f, key * sizeof(STUDENT), SEEK_SET);//ne aduce la inceputul recordului nou adaugat;
            fwrite(&x, sizeof(STUDENT), 1, f);//write a record
        }//everything repets with a new key
        //printf_s("Enrollment number (or CTRL+Z): ");
        scanf_s("%d", &key);
    }

    fclose(f);
    fclose(stdin);

    printf("\nDone. File <%s> was created. Press a key.", numefr);
    _getch();
}

Solution

  • there are two ways to remove a record from a file:

    1) copy into a new file all the records before the one to be deleted, skip the record to be deleted, then copy all the rest of the records then delete the original file then rename the new file to the original file name.

    2) step through the file until find the record to be deleted. Then, in a loop copy the next record to the current record then truncate the file by 1 record length

    All that (above) can be very messy and time consuming. Suggest: just set the field 'is' in the record to be 'deleted' to 0