Updating and deleting contents of a file - c

I have a file named as Empdata.txt having fields as "(%s)id,(%s)name,(%d)salary". Firstly, i am inserting some values to it. Now i want to update record having the same id as given by the user. I am using this code:
struct employee
{
char id[100];
char name[100];
int sal;
};
int main()
{
FILE *ptr;
struct employee e;
ptr=fopen("Empdata.txt","w+");
printf("Enter Employee id");
scanf("%s",id);
while(!feof(ptr))
{
fread(&e,sizeof(e),1,ptr);
if(strcmp(id,e.id)==0)
{
printf("Enter name");
scanf("%s",e.name);
printf("Enter basic salary");
scanf("%d",&e.sal);
fwrite(&e,sizeof(e),1,ptr);
}
};
fclose(ptr);
}
But it is not matching the ids. So it is not updating even. Further i have to perform delete operation also. I am not getting how to delete record having a particular id.
Please assume all variables are initialized properly.

If you plan to update a record, you will have to both read, and write records. Hence the "w" file mode is insufficient (ie:fopen("Empdata.txt","w");). Perhaps the "r+" mode would be more appropriate?
First thing in your while() loop, you need to read a record from your file.
At the bottom of the loop, you need to note your file position (ie:ftell()), so that if the next record is a match, you will know where to fseek() back to in order to write the updated record back to the file.
long position=0;
...
while(!feof(ptr))
{
fread(&e,sizeof(e),1,ptr);
if(strcmp(id,e.id)==0)
{
...
}
position=ftell(ptr);
};
If you find a matching record (ie:if(strcmp(id,e.id)==0)), the very last thing you should do is re-position to the beginning of the matching record (ie:fseek()) and then write the updated record. And since you have accomplished your task, you should break out of the while loop and return.
{
...
fseek(ptr, position, SEEK_SET);
fwrite(&e,sizeof(e),1,ptr);
}

Related

Display record function to display Non-empty records not displaying records

Setting up a database which takes the input from a user(First name, last name, ID number , etc..) and inputs the information into a binary file, to update information , delete records, and update any information provided. All other functions seem to be functioning properly(Dont mind the bad code, im fairly new to programming) besides the function to display the non empty records. the information seems to be getting saved into the files because the other functions have access to it(all the same file pointer). I've checked to see if the file was being overwritten by the initialization of the empty file and that hasn't been the case to my understanding.
I've checked to see if the file was being overwritten by the initialization of the empty file and that hasn't been the case to my understanding. I've also tried updating the the if statement in the DisplayRecord function so that it would read all files and display only the ones that have an established ID number but it still shows null when the function is ran.
// fopen opens the file; exits if file cannot be opened
if ((cPtr = fopen("patient.dat", "rb")) == NULL) {
puts("File could not be opened.");
}//end If
else {
printf( "Patient ID\t Last Name\t first name\t DOB \tGender\t Doctor ID\t
Doctor last name\t Room Number\n" );
struct PatientData {
unsigned int Pat_ID; //ID number
char F_Name[25];//first name
char L_Name[25]; //last name
char Phone_num[20] ; //Phone number
char gender[2];
unsigned int doctor_ID;
char doc_LN[25];
unsigned int room_num;
char DoB[10];
};
//read all records until eof
while(!feof(cPtr)){
//create blank set to compare to data on file
struct PatientData Patient= { 0, "","","","",0,"", 0,"" };
int result=fread(&Patient,sizeof(struct PatientData), 1 , cPtr);
if(result!=0 && Patient.Pat_ID!=0){
printf("%-d%-15s%-15s%-10s%-12s%-15d%-15s%-10d\n",
Patient.Pat_ID,
Patient.L_Name,Patient.F_Name,Patient.DoB,Patient.gender,
Patient.doctor_ID, Patient.doc_LN,Patient.room_num);
}
fclose(cPtr); // fclose closes the file
Its suppose to display all records that have information in it. but the actual output is not showing any records.

Reading different datatype from .txt file

I want to read data from a text file and store the data.
I can not all the data using getc() as it will take all the data at once, and I do not know how to distribute that for my use.
Data is in form of:
John
Sebastian
1
2 //Number of notes(So, when I read this value and run a loop to collect all
notes)
12 //note 1
21 //note 2
#include <stdio.h>
struct StudentDetails
{
char firstName[100], secondName[100];
int notes[100][30], id;
struct StudentDetails *next;
};
int main()
{
FILE *input;
input = fopen("input.txt", "r");
if (!input)
{
while (input != EOF)
{
//what to do to store in different variable rather in one.
}
}
else
{
printf("File not found");
}
}
Please try fread() function for reading a record from a file and fwrite(), it's used to write a record to the file.
eg: fwrite(&sd,sizeof(sd),1,input);
for student record no need of struct StudentDetails *next; (we are not doing anything like linked list, we just write different student record in a file. So you just define structure variable as StudentDetails SD in main that is more than enough each iteration of loop you can write one student record to file.)
for reading you can use
while(fread(&sd,sizeof(sd),1,input) > 0 )
{
printf("Name:%s",sd.name);//this you can do ...
}
I hope it will help you :)

search in a file in c

the data on the file.txt are placed as shown.
My Code is this:
int searchBookname()
{
FILE *myFile=fopen("file.txt","r+");
if (myFile!=NULL) // file exists
{
char tmp1[512];
char tmp2[512];
while(fgets(tmp1,512,myFile)!=EOF)
{
puts("Insert the Book Name: ");
scanf("%s",tmp2);
if(strstr(tmp1,tmp2)!=NULL){
printf("the book is found: %s\n\n",tmp1);
}else{
puts("\nSorry there was no Match with this name! Maybe Book is not recorded yet :(\n");
}
}
}else{ // file doesn't exist
puts("\nDatabase is not created yet. Please record a new book to create a simple database\n");
exit(0);
}
fclose(myFile); // closing the file
}
It keeps skipping the if statement 2 times for some reason and on the
3rd time it prints the correct result.
This happen for whatever book I try to search.
See here
How can I make it find the result without skipping the if statement.
You read the file line by line. So in the third loop/line there is a record with 'book1'. Code is working correctly as it is. Maybe you want to ask the user for a book name outside of the while loop and search in every line for the given book name. If there is, you can print you message and break from the loop.
int searchBookname()
{
FILE *myFile=fopen("file.txt","r+");
if (myFile != NULL) // file exists
{
char tmp1[512], tmp2[512];
puts("Insert the Book Name: ");
scanf("%s",tmp2);
// Skip the first two lines of the file
fgets(tmp1,512,myFile);
fgets(tmp1,512,myFile);
while(fgets(tmp1,512,myFile) != EOF)
{
if(strstr(tmp1,tmp2) != NULL)
{
printf("the book is found: %s\n\n",tmp1);
break;
}
else
{
puts("\nSorry there was no Match with this name! Maybe Book is not recorded yet :(\n");
}
}
}
else
{ // file doesn't exist
puts("\nDatabase is not created yet. Please record a new book to create a simple database\n");
exit(0);
}
fclose(myFile); // closing the file
}
It is obvious.
First 2 lines of file are following:
Record_Date ...
-> (empty line)
You are reading file line by line and check book name in each line. So if must fail for first 2 times.
If you want to find a book in your file, your approach is incorrect. There are different approaches for this, but simplest is reading book records into an structure array, and then look for book name in that array.

why isn't fwrite overwriting my data in wb+?

I wrote a small program in C that creates a list of students in a binary file. I call function fsearch() (below) to search for a specified student and change his data, but the data seems not to be modified.
// the file is opened in mode "wb+"
int fsearch(FILE *f)
{
student s;
float matsearch;
printf("enter the matricule you want to find ");
scanf("%f",&matsearch);
rewind(f); // starting the search from the beginning
while(fread(&s,sizeof(student),1,f)==1 && s.mat!=matsearch);
if(s.mat==matsearch)
{
printf("we found what searched for\n");
printf("name: %s\n",s.fname);
printf("last name: %s\n",s.lname);
printf("matricule: %.f\n",s.mat);
fseek(f,-sizeof(student),SEEK_CUR);
student a;
scanf("%s",&(a.fname));
scanf("%s",&(a.lname));
scanf("%d",&(a.mat));
if(fwrite(&a,sizeof(student),1,f)==1)
{
printf("successfully wrote"); // this message does get printed
}
return(1); // successfully found
}
printf("we didn't find what you searched for\n");
return(0);
}
In addition to the one posted by bluesawdust, I found some other mistakes in the code:
// the file is opened in mode "wb+": this means that your file was destroyed on open (see here). You might want to use "rb+"
since you didn't initialize your student s structure (and no record was ever written in it because of my previous point) s.mat contains a random value
scanf("%d",&(a.mat));: as for printf, you should change the format string to "%f" (but actually you should use a string type, comparing floats with == is not good practice because of the roundings)
sizeof(student) is unsigned, so negating it is not appropriate here. You should cast it to an int before negating.

Accessing data from file A using an element shared with a file B (Foreign Keys)

I have a file car.txt and a file reservation.txt. Both the files have a reservation number (Rxxx).
I want to use the reservation number from reservation.txt to print the details of the car with the corresponding reservation number. Or more accurately, I'm trying to find the details of all the cars that are available at any given date.
car.txt:
(from let to right: reservationID, carID, carYOM, carMake, carModel, carFuel, catagory)
R002;V001;2003;Toyota;Camry;Petrol;Budget
R007;V002;2005;Toyota;Prius;Petrol;Economy
R001;V003;1999;Ford;Falcon;Petrol;Midsize
R008;V004;2007;Ford;Territory;Diesel;Fullsize
R011;V005;2010;Ferrari;599;Petrol;Fullsize
R035;V006;1998;Holden;Comadore;Diesel;Midsize
R006;V007;2008;Honda;Civic;Petrol;Budget
R004;V008;2000;Mazda;MX5;Petrol;Economy
reservation.txt:
(from let to right: reservationID, customerID, reservationStartDate, reservationStartTime, reservationEndDate, reservationEndTime)
R001;C005;12/02/2012;09:15A.M;15/03/2012;05:00P.M
R002;C002;15/04/2012;10:00A.M;22/04/2012;10:30A.M
R003;C003;16/01/2012;02:11P.M;15/04/2012;12:00P.M
R004;C004;05/05/2012;03:00P.M;08/05/2012;10:40A.M
R005;C005;15/04/2012;10:00A.M;23/04/2012;05:00P.M
R006;C006;11/04/2012;05:30P.M;15/04/2012;10:00A.M
R010;C008;15/05/2012;03:15P.M;18/05/2012;11:00A.M
R011;C007;15/04/2012;11:40P.A;23/04/2012;09:00A.M
If I enter any date It only gets up to the point where it decides if the entered date is between the reservation start and end date. "all the cars are available".
However, if I enter 13/02/2012, It prints "no matching resID in cars.txt" 7 times.
The code in question:
#include <stdio.h>
#include <string.h>
#define MAX_CAR 100
#define MAX_RES 100
int main(){
typedef struct{ //car struct
char reservationID[20];
char carID[20];
char carYOM[20];
char carMake[20];
char carModel[50];
char carFuel[20];
char catagory[20];
} car_t;
typedef struct{ //res struct
char reservationID[20];
char customerID[20];
char reservationStartDate[20];
char reservationStartTime[20];
char reservationEndDate[50];
char reservationEndTime[20];
} res_t;
car_t car[MAX_CAR]; //car array
res_t reservation[MAX_RES]; //res array
FILE *carHandle;
FILE *resHandle;
char line[100];
char *item;
int rescount = 0;
int carcount =0;
int k;
int i;
int option;
char choice[20];
resHandle = fopen("reservation.txt","r");
while (fgets(line, 99, resHandle)){ //cut up the reservation file line by line and put the bits into the res array.
item = strtok(line,";");
strcpy(reservation[rescount].reservationID,item);
item = strtok(NULL,";");
strcpy(reservation[rescount].customerID,item);
item = strtok(NULL,";");
strcpy(reservation[rescount].reservationStartDate,item);
item = strtok(NULL,";");
strcpy(reservation[rescount].reservationStartTime,item);
item = strtok(NULL,";");
strcpy(reservation[rescount].reservationEndDate,item);
item = strtok(NULL,"\n");
strcpy(reservation[rescount].reservationEndTime,item);
rescount++;
}
fclose(resHandle);
carHandle = fopen("car.txt","r");
while (fgets(line, 99, carHandle)){ //cut up the car file line by line and put the bits into the car array.
item = strtok(line,";");
strcpy(car[carcount].reservationID,item);
item = strtok(NULL,";");
strcpy(car[carcount].carID,item);
item = strtok(NULL,";");
strcpy(car[carcount].carYOM,item);
item = strtok(NULL,";");
strcpy(car[carcount].carMake,item);
item = strtok(NULL,";");
strcpy(car[carcount].carModel,item);
item = strtok(NULL,";");
strcpy(car[carcount].carFuel,item);
item = strtok(NULL,"\n");
strcpy(car[carcount].catagory,item);
carcount++;
}
fclose(carHandle);
printf("Enter todays date:");
scanf("%s", choice);
for (k=0;k<=rescount; k++){
if (strcmp(choice,reservation[k].reservationEndDate)<0 && strcmp(choice,reservation[k].reservationStartDate)>0){
for (i=0;i<=carcount; i++){
if (strcmp(car[k].reservationID,reservation[i].reservationID)==0){
printf("\nreservationID: %s\nreservationStartTime: %s\ncustomerID: %s\ncarid: %s\nyom: %s\nmake: %s\nmodel: %s\nfueltype: %s\ncategory: %s\n\n", car[k].reservationID, reservation[i].reservationStartTime, reservation[i].customerID, car[k].carID, car[k].carYOM, car[k].carMake, car[k].carModel, car[k].carFuel, car[k].catagory);
//printf("This works");
goto outofloop;
}else printf("\n\nno matching resID in cars.txt\n");
}
}
else printf("\nall the cars are available\n");
break;
}
outofloop:
return(0);
}
Any help would be appreciated. :)
EDIT: Updated code.
This is the output, still wrong :(:
Enter todays date:13/02/2012
no matching resID in cars.txt
reservationID: R002
reservationStartTime: 10:00A.M
customerID: C002
carid: V001
yom: 2003
make: Toyota
model: Camry
fueltype: Petrol
category: Budget
Press any key to continue . . .
Enter todays date:13/02/2012
all the cars are available
Press any key to continue...
You're not counting the number of cars and reservations correctly:
In both loops (the one that reads cars, and the one that reads reservations), you're using reccount as the counter.
You need to use two counters, carcount and rescount.
Later on, then, you need to use carcount and rescount in your for loops.
for (k=0;k<=rescount; k++){
if (strcmp(choice,reservation[k].reservationEndDate)<0 && strcmp(choice,reservation[k].reservationStartDate)>0){
for (i=0;i<=carcount; i++){
You should also consider dynamically allocating memory for the car and reservation arrays, as well as for the character arrays inside car_t and reservation_t, since your current code will (even when the obvious bug is fixed) segfault or give unexpected results as soon as your input files have over MAX_CAR/MAX_RES lines, or the strings in the lines are too long.
Update
There are still several issues with your updated code:
You should not store data that's not supposed to be a string in a string variable. Store as much as possible in integer or unsigned variables, especially IDs and dates.
Speaking about dates: Simply use time(NULL) to get the current time in UNIX time format ("seconds from 1970-01-01 00:00"). Store all dates as an integer in UNIX time.
When reading the file, check if carcount is greater than CAR_MAX
for(carcount = 0; carcount < CAR_MAX; carcount++)
You should use fscanf when reading the textfile:
if(fscanf(filehandle, "R%03u...\n", &car[carcount].reservationID, ...) == EOF)
break;
This will make your file scanning much more robust and turn it into a one-liner.
Avoid string comparisions wherever possible. Instead, use 'real datatypes'.
Avoid gotos, really. It is true that Linux kernel developers use them, but they know what they're doing.
Your outer for loop contains a break statement that will, in every case, break the loop execution after the first run. You probably forgot braces after 'else'.
I think your program flow logic contains some errors. You printf("\n\nno matching resID in cars.txt\n") after every single car.
In general, have you tried debugging your code? gdb is a really powerful utility. You can use it to follow the program flow, pause your program at look at variable contents at any time.
I have fixed the issue. The problem was using resID as a common identifier instead of carID.
Thanks for the help everyone.

Resources