Getting the same output twice when reading a file - c++

I am having a problem with the following program,
#include<iostream>
#include<fstream>
#include<windows.h>
using namespace std;
class student
{
int rollno;
char name[50];
int cls;
int marks;
char grade;
public:
void getdata()
{
cout<<"Enter Roll No.: ";
cin>>rollno;
cout<<"Enter Name: ";
cin>>name;
cout<<"Enter Class: ";
cin>>cls;
cout<<"Enter Marks: ";
cin>>marks;
if(marks>=75)
{
grade='A';
}
if(marks>=60 && marks<75)
{
grade='B';
}
if(marks>=45 && marks<60)
{
grade='C';
}
if(marks>=35 && marks<45)
{
grade='D';
}
if(marks<35)
{
grade='F';
}
}
void display()
{
cout<<"\nRoll No.: "<<rollno;
cout<<"\nName: "<<name;
cout<<"\nClass: "<<cls;
cout<<"\nMarks: "<<marks;
cout<<"\nGrade: "<<grade<<endl;
}
int rno()
{
return rollno;
}
} s1, s2, s3;
void append()
{
fstream fo ("STUDENT.DAT",ios::binary | ios::app | ios::out);
if(!fo)
{
cout<<"CANNOT OPEN FILE!!!!!";
}
else
{
s1.getdata();
fo.write((char*)&s1, sizeof(s1));
}
fo.close();
}
void sdisplay()
{
fstream fi ("STUDENT.DAT",ios::binary | ios::in);
if(!fi)
{
cout<<"\nNO RECORDS !!!!";
}
else
{
while(!fi.eof())
{
fi.read((char*)&s2, sizeof(s2));
if(s2.rno()!='\0')
{
s2.display();
}
}
}
fi.close();
}
void rdisplay()
{
int n, found;
fstream fi ("STUDENT.DAT", ios::in | ios::binary);
if(!fi)
{
cout<<"\nNO RECORDS !!!!";
}
else
{
cout<<"\nEnter Roll No. to be displayed: ";
cin>>n;
while(!fi.eof())
{
fi.read((char*)&s3, sizeof(s3));
if(s3.rno()==n)
{
s3.display();
found=1;
}
}
if(found!=1)
{
cout<<"\nCannot find roll no!!";
}
}
fi.close();
}
int main()
{
char ch='y';
int choice, n;
while(ch=='y' || ch=='Y')
{
cout<<"\n1. Append Data to File";
cout<<"\n2. Display Entire File";
cout<<"\n3. Search & Display record based on Roll No.";
cout<<"\n4. Exit";
cout<<"\n\n Enter your choice (1-4): ";
cin>>choice;
switch(choice)
{
case 1:
append();
break;
case 2:
sdisplay();
break;
case 3:
rdisplay();
break;
case 4:
exit(0);
break;
default:
cout<<"\nWrong Choice !!!!!";
break;
}
cout<<"\n\nDo you want to continue? (Y/N)";
cin>>ch;
}
}
So, After appending the data, When I go to Display the data (option 2 & 3) it outputs the same entry twice.
Append Data to File
Display Entire File
Search & Display record based on Roll No.
Exit
Enter your choice (1-4): 2
NO RECORDS !!!!
Do you want to continue? (Y/N)y
Append Data to File
Display Entire File
Search & Display record based on Roll No.
Exit
Enter your choice (1-4): 1 Enter Roll No.: 23 Enter Name: James Enter
Class: 12 Enter Marks: 85
Do you want to continue? (Y/N)y
Append Data to File
Display Entire File
Search & Display record based on Roll No.
Exit
Enter your choice (1-4): 2
Roll No.: 23 Name: James Class: 12 Marks: 85 Grade: A
Roll No.: 23 Name: James Class: 12 Marks: 85 Grade: A
Do you want to continue? (Y/N)n
Process returned 0 (0x0) execution time : 25.013 s Press any key to
continue.
Can someone help me?
Thanks

eof() won't get set until you read past the end, which won't happen until your 2nd read. That read will do nothing, so it won't overwrite s2, it'll just fail - so you'll end up printing that row again.
The solution is don't loop over eof(). Just loop over read():
while(fi.read((char*)&s2, sizeof(s2)))
{
s2.display();
}

Related

Delete and Update products from a text file in C++

Below is my code in C++ about updating and deleting particular Product from a text file. It really works but after functioning, it create the things in the command box picture. Parallel to that, text file appears to create space according to product view in command box picture. The two functions are mostly the same.
void delete_Product(struct Product p)
{
fstream exa;
fstream temp;
char code[25];
exa.open("example.txt", ios::in);
temp.open("temp.txt", ios::out);
cin.ignore();
cout<<"\nEnter Product Code : ";
cin.getline(code,25);
while (!exa.eof())
{
exa.getline(p.P_code,25,'\n');
exa.getline(p.P_name,25,'\n');
exa.getline(p.meg,25,'\n');
exa.getline(p.expiry,25,'\n');
exa.getline(p.producer,25);
search_Product(p,code);
if (strcmp(p.P_code,code)==0)
{
continue;
} else
{
temp<<p.P_code<<'\n'<<p.P_name<<'\n'<<p.meg<<'\n'<<p.expiry<<'\n'<<p.producer<<'\n';
}
}
temp.close();
exa.close();
exa.open("example.txt", ios::out);
temp.open("temp.txt", ios::in);
while (!temp.eof())
{
temp.getline(p.P_code,25,'\n');
temp.getline(p.P_name,25,'\n');
temp.getline(p.meg,25,'\n');
temp.getline(p.expiry,25,'\n');
temp.getline(p.producer,25);
exa<<p.P_code<<'\n'<<p.P_name<<'\n'<<p.meg<<'\n'<<p.expiry<<'\n'<<p.producer<<'\n';
}
temp.close();
exa.close();
remove("temp.txt");
cout<<"Done!";
}
void update_Product(struct Product p)
{
fstream exa;
fstream temp;
char code[25];
exa.open("example.txt", ios::in);
temp.open("temp.txt", ios::out);
cin.ignore();
cout<<"\nEnter Product Code : ";
cin.getline(code,25);
while (!exa.eof())
{
exa.getline(p.P_code,25,'\n');
exa.getline(p.P_name,25,'\n');
exa.getline(p.meg,25,'\n');
exa.getline(p.expiry,25,'\n');
exa.getline(p.producer,25);
search_Product(p,code);
if (strcmp(p.P_code,code)==0)
{
cout<<"\n\nPlease update the selected Product";
cout<<"\nEnter Product's ID: ";
cin>>p.P_code;
cin.ignore();
cout<<"Enter Product's Name: ";
cin.getline(p.P_name, 25);
cout<<"Enter Manufacturing date: ";
cin>>p.meg;
cout<<"Enter Expiry date: ";
cin>>p.expiry;
cin.ignore();
cout<<"Enter Producer's Name: ";
cin.getline(p.producer, 25);
temp<<p.P_code<<'\n'<<p.P_name<<'\n'<<p.meg<<'\n'<<p.expiry<<'\n'<<p.producer<<'\n';
}
else
{
temp<<p.P_code<<'\n'<<p.P_name<<'\n'<<p.meg<<'\n'<<p.expiry<<'\n'<<p.producer<<'\n';
}
}
temp.close();
exa.close();
exa.open("example.txt", ios::out);
temp.open("temp.txt", ios::in);
while (!temp.eof())
{
temp.getline(p.P_code,25,'\n');
temp.getline(p.P_name,25,'\n');
temp.getline(p.meg,25,'\n');
temp.getline(p.expiry,25,'\n');
temp.getline(p.producer,25);
exa<<p.P_code<<'\n'<<p.P_name<<'\n'<<p.meg<<'\n'<<p.expiry<<'\n'<<p.producer<<'\n';
}
temp.close();
exa.close();
remove("temp.txt");
cout<<"Done!";
}
My full code is on Google Drive.
Below are screenshots of the output:

Why is the data not getting properly written/read in this file?

The following code just accepts some data from the user in an object and writes it in a binary file. The first object gets written fine but after that it gets messed up.
Below is the output on reading the file after writing the first object onto it.
ROLL NO. NAME MARKS
234 Sansa 67
All fine and just as I expect. But when I append another object in the file, then this happens.
ROLL NO. NAME MARKS
234 SansSnow 78
564 Jon Snow 78
The roll numbers remain intact however names of the previous objects gets mixed up with the last object's and their marks get overwritten by the marks of the last object.
Why is it happening?
CODE:
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
fstream file;
class Student
{
protected:
int rollno;
char name[30];
float marks;
public:
void getData()
{
cout<<"ENTER THE DATA..."<<endl<<endl;
cout<<"Roll Number : ";
cin>>rollno;
fflush(stdin);
cout<<"Name : ";
cin.getline(name,30);
cout<<"Marks : ";
cin>>marks;
}
void displayData()
{
cout<<"\n"<<rollno;
cout<<setw(17)<<name;
cout<<setw(13)<<marks;
}
void writeData()
{
file.open("StudentData.dat", ios::app|ios::binary);
file.write((char*)this, sizeof(this));
file.close();
}
void readData()
{
file.open("StudentData.dat",ios::in|ios::binary);
while(file.read((char*)this, sizeof(this)))
{
displayData();
}
file.close();
}
};
Student S1;
int main()
{
cout<<"\nMAIN MENU"<<endl<<endl;
cout<<"1. Enter data and write to file\n";
cout<<"2. Read data from file and display\n";
cout<<"3. Exit\n\n";
cout<<"Enter your choice : ";
int choice;
cin>>choice;
switch(choice)
{
case 1:{
S1.getData();
S1.writeData();
cout<<endl<<endl;
cout<<"Data written to file successfully!"<<endl;
main();
break;
}
case 2:{
cout<<"ROLL NO."<<setw(10)<<"NAME"<<setw(15)<<"MARKS";
S1.readData();
cout<<endl;
main();
break;
}
case 3:{
exitop:
char confirmExit;
cout<<"\nAre you sure you want to exit? (Y/N) : ";
cin>>confirmExit;
if(confirmExit=='y' or confirmExit=='Y')
exit(0);
else if(confirmExit=='n' or confirmExit=='N')
{
cout<<"Exit Aborted.\n\n";
getchar();
main();
}
else{
cout<<"Invalid Input!";
goto exitop;
}
}
default:{
cout<<"Invalid Input!";
break;
}
}
return 0;
}
You’re only reading and writing 8 bytes. this is a pointer so sizeof(this) is 8 (on a 64 bit machine). What you actually want to do is get the size of the object instead so use sizeof(*this) or sizeof(Student).

Output file overwriting incorrectly

This is just to go with my last question, someone asked me to upload the file so I'll cut out all the useless functions and have the main code especially that having to do with the output, this is my 3rd question on stack overflow so I still don't know much about how it works, if you want to answer please check my last (2nd) question for details. Here is the code:
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;
const int MAX_SIZE = 1000;
struct Student
{
string studentID;
string firstName;
char midInitial;
string lastName;
};
void menu()
{
cout<<" CLASS ROSTER APPLICATION"<<endl;
cout<<"========================================="<<endl;
cout<<"ADD a student record..................[A]"<<endl;
cout<<"DELETE a student......................[D]"<<endl;
cout<<"EDIT a student record.................[E]"<<endl;
cout<<"INQUIRY about a student...............[I]"<<endl;
cout<<"LIST all students.....................[L]"<<endl;
cout<<"QUIT the system.......................[Q]"<<endl;
}
int linearSearch(const Student roster[], int numStuds, string sID)
{
int i;
for (i=0; i<numStuds; i++)
{
if (roster[i].studentID == sID)
return i;
}
return -1;
}
void selSort(Student roster[], int numStuds)
{
int minIDPos;
Student tempStudRecord;
int i,j;
for (i=0; i<numStuds-1; i++)
{
minIDPos = i;
for (j=i+1; j<numStuds; j++)
{
if (roster[j].studentID < roster[minIDPos].studentID)
minIDPos = j;
}
tempStudRecord = roster[i];
roster[i] = roster[minIDPos];
roster[minIDPos] = tempStudRecord;
}
}
void listStudents(const Student roster[], int numStuds)
{
cout<<"C L A S S R O S T E R"<<endl;
cout<<"Student ID # First Name M.I. Last Name"<<endl;
cout<<"---------------------------------------------"<<endl;
int i2=0; //just a counter.
while (i2<numStuds)
{
cout<<left;
cout<<setw(14)<<roster[i2].studentID<<setw(13)<<roster[i2].firstName;
cout<<roster[i2].midInitial<<". "<<roster[i2].lastName;
cout<<endl;
i2++;
}
cout<<right;
cout<<"---------------------------------------------"<<endl;
cout<<"Enrollment: "<<i2<<endl;
}
int main()
{
Student roster[MAX_SIZE];
fstream inFile;
fstream outFile;
string filename, sID;
Student newStudent;
int numStuds = 0;
char choice;
int i;
cout<<"Enter the name of the data file> ";
cin>>filename;
/** 7. open the data file for input **/
inFile.open(filename.c_str(), ios::in);
if (inFile)
{
/** 8. write a while loop to read the data from the file
into the roster array; the numStuds (number of Students)
must be updated as the records are read from the file.
Also, close the file after its contents are read into the
roster array.
**/
while (!inFile.eof() && numStuds < MAX_SIZE)
{
inFile>>roster[numStuds].studentID>>roster[numStuds].firstName;
inFile>>roster[numStuds].midInitial>>roster[numStuds].lastName;
numStuds++;
}
inFile.close();
}
do
{
cout<<endl;
menu();
cout<<endl;
cout<<"Select an option-> ";
cin>>choice;
cout<<endl;
switch(toupper(choice))
{
case 'A': cout<<"Enter the student ID #> ";
cin>>newStudent.studentID;
cout<<"Enter the student's first name> ";
cin>>newStudent.firstName;
cout<<"Enter the student's middle initial> ";
cin>>newStudent.midInitial;
cout<<"Enter the student's last name> ";
cin>>newStudent.lastName;
addStudent(roster,numStuds,newStudent);
break;
case 'D': /** 9. write code here to remove a student from the roster **/
cout<<"Enter the student ID Number: ";
cin>>sID;
deleteStudent(roster, numStuds, sID);
break;
case 'E': /** 10. write code to edit the record for a student with a specified ID # **/
cout<<"Enter the student ID Number: ";
cin>>sID;
editStudent(roster, numStuds, sID);
break;
case 'I': /** 11. write code to perform an inquiry (obtain full name) on a student with
with a specified ID # **/
cout<<"Enter the student ID Number: ";
cin>>sID;
studentInquiry(roster, numStuds, sID);
break;
case 'L': /** 12. write code to sort and then generate class roster **/
selSort(roster, numStuds);
listStudents(roster, numStuds);
break;
case 'Q': break;
default: cout<<"Invalid menu choice...try again!"<<endl;
}
}while(toupper(choice) != 'Q');
/** 13. open the data file in output mode and error-check to ensure
that it was successfully opened.
**/
outFile.open(filename.c_str(), ios::out);
if (!outFile)
{
cout<<"Unable to open "<<filename<<" for output. "<<endl;
return -1;
}
/** 14. overwrite the data file in the order:
student ID, firstname, middle initial and last name, one record per line.
make sure that you have spaces between the fields.
**/
for (i=0;i<numStuds;i++)
{
outFile<<roster[i].studentID<<" "<<roster[i].firstName<<" ";
outFile<<roster[i].midInitial<<" "<<roster[i].lastName<<endl;
}
/** 15. close the output file **/
outFile.close();
return 0;
}
This here
while (!inFile.eof() && numStuds < MAX_SIZE) {
inFile >> roster[numStuds].studentID >> roster[numStuds].firstName;
inFile >> roster[numStuds].midInitial >> roster[numStuds].lastName;
numStuds++;
}
Will leave the value of numStuds one higher than it should be, as inFile.eof() will only return true once the end of file has been reached, which won't occur until you have actually tried to read past the end of the file.
One way of fixing it would be to change it to
while (numStuds < MAX_SIZE &&
(inFile >> roster[numStuds].studentID >> roster[numStuds].firstName >>
roster[numStuds].midInitial >> roster[numStuds].lastName)
) {
numStuds++;
}
Although you're better off defining a function that reads the struct for you
std::istream& operator>>(std::istream& stream, Student& student)
{
stream >> student.studentID >> student.firstName
>> student.midInitial >> student.lastName;
return stream;
}
Which will work as follows:
while (inFile >> roster[numStuds]) {
numStuds++;
}
As suggested by #JoachimPileborg the following would be even better (once operator>> is defined for your struct):
std::vector<Student> roster;
//...
std::copy(
std::istream_iterator<Student>(inFile),
std::istream_iterator<Student>(),
std::back_inserter(roster)
);

How do I compare a string variable to an array of strings created from a file

Hello Ive been working on a program where I have a file with 3 columns containing both the inauguration year and departure year of a president, along with the name of the president. Im trying to have the user input a president and have the program return the start and stop year. I began by opening the file (which opens correctly) and making 3 arrays, 2 integer arrays and one string array. The program runs but when I press 2 regardless of what name I enter the bool stays false. The file can be found here: http://pastebin.com/8h3BJxGD
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
char junk, x;
int start[100],stop[100],year,i,count=0;
string names[100],president;
ifstream file;
file.open("presidents.txt");
if(file.fail())
cout<<"failed to open file"<<endl;
for(i=0;file>>start[i];i++)
{
file>>stop[i];
file.get(junk);
getline(file,names[i]);
cout<<start[i]<<stop[i]<<names[i]<<endl;
count++;
}
do
{
cout<<"What would you like to know?"<<endl;
cout<<"Press 1 for who was President in what year"<<endl;
cout<<"Press 2 for the years served by a President"<<endl;
cout<<"Press 3 to stop"<<endl;
cin>>x;
if(x=='1')
{
bool valid=false;
cout<<"Enter a year: "<<endl;
cin>>year;
for(i=0;i<count;i++)
{
if(start[i]<=year&&stop[i]>=year)
{
cout<<names[i]<<endl;
cout<<endl;
valid=true;
}
}
if(valid==false)
{
cout<<"Invalid year"<<endl;
cout<<endl;
}
}
if(x=='2')
{
bool valid=false;
cout<<"Enter a President: "<<endl;
cin>>president;
getline(cin,president);
for(i=0;i<count;i++)
{
if(president==names[i])
{
cout<<start[i]<<"-"<<stop[i]<<endl;
cout<<endl;
valid=true;
}
}
if(valid==false)
{
cout<<"Please be more percise"<<endl;
cout<<endl;
}
}
}
while (x!='3');
cin>>junk;
return 0;
}
Here, problem is not with the comparison, but with input string into president variable, try printing president variables value, you will understand the problem.
You need to add following line after reading x.
cin.ignore(); //add this line after cin>>x;
This will remove \n from the input buffer and will not cause any issue while reading president string. You need to take care of such issues while combining use of formatted input (i.e. >>) with unformatted input (i.e. get(), getline() etc).
Below is the modified code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
char junk, x;
int start[100],stop[100],year,i,count=0;
string names[100],president;
ifstream file;
file.open("president.txt");
if(file.fail())
cout<<"failed to open file"<<endl;
for(i=0;file>>start[i];i++)
{
file>>stop[i];
file.get(junk);
getline(file,names[i]);
cout<<start[i]<<stop[i]<<names[i]<<endl;
count++;
}
do
{
cout<<"What would you like to know?"<<endl;
cout<<"Press 1 for who was President in what year"<<endl;
cout<<"Press 2 for the years served by a President"<<endl;
cout<<"Press 3 to stop"<<endl;
cin>>x;
cin.ignore();
if(x=='1')
{
bool valid=false;
cout<<"Enter a year: "<<endl;
cin>>year;
for(i=0;i<count;i++)
{
if(start[i]<=year&&stop[i]>=year)
{
cout<<names[i]<<endl;
cout<<endl;
valid=true;
}
}
if(valid==false)
{
cout<<"Invalid year"<<endl;
cout<<endl;
}
}
if(x=='2')
{
bool valid=false;
cout<<"Enter a President: ";
getline(cin,president);
for(i=0;i<count;i++)
{
if(president==names[i])
{
cout<<start[i]<<"-"<<stop[i]<<endl;
cout<<endl;
valid=true;
}
}
if(valid==false)
{
cout<<"Please be more percise"<<endl;
cout<<endl;
}
}
}
while (x!='3');
cin>>junk;
return 0;
}
Following is the output:
What would you like to know?
Press 1 for who was President in what year
Press 2 for the years served by a President
Press 3 to stop
2
Enter a President: Theodore Roosevelt
1901-1909
if(president==)
if president == what???
Also,
getline(cin,president); //why this line?
if you have already read the file and put into data structure, then just search through the data structure for the name of the president that the user enters...if you find it, keep track of the index as you have done and print out the start[] and stop[] at the same index...

Binary structure delete error

This is the whole program. Right now,the delete function does not write to the temp file. I'll try to change str array to string and see if it helps.
The program is supposed to read write edit search and sort binary file with structures.
#include <cstdlib>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include<string>
#include<limits>
#include<iomanip>
#include<stdio.h>
#include <errno.h>
using namespace std;
const int SIZE=40;
char typedef str[SIZE];
char fname[]="c:/solident.dat";
char tname[]="c:/temp.dat";
struct Rec{int id;str lname,fname;};
//prototypes
void menu(string&);
void engine(string&,Rec&,fstream&,fstream&,int,char[],char[]);
void openFile(char[]);
void addRec(Rec&,char[]);
void delAll(char[]);
void listAll(Rec&,fstream &,char[]);
void appRec(Rec&,fstream &,char[]);
void delRec(Rec&,fstream &, fstream &,char[],char []);
void srcRec(Rec&,fstream& ,char[]);
void modRec(Rec &J,fstream &outfile, char fname[]);
void sort();
int main(int argc, char *argv[])
{
string choice;
Rec Student;
fstream infile;
fstream outfile;
do
{
menu(choice);
engine(choice,Student,infile,outfile,SIZE,fname,tname);
} while(choice[0]!='0');
system("PAUSE");
return EXIT_SUCCESS;
}
//function menu
void menu(string &choice)
{
cout<<"\n\n\n\t\t========================";
cout<<"\n\n\t\tMENU \n";
cout<<"\n\t\t========================\n\n";
cout<<"\t\t[1] Open/check file\n";
cout<<"\t\t[2] Add records\n";
cout<<"\t\t[3] Append records\n";
cout<<"\t\t[4] Search for a record\n";
cout<<"\t\t[5] Delete a record\n";
cout<<"\t\t[6] Delete all records\n";
cout<<"\t\t[7] Modify a record\n";
cout<<"\t\t[8] List all records\n";
cout<<"\t\t[9] Sort all records\n";
cout<<"\t\t[0] Exit\n";
cout<<"\n\t\t========================= \n";
cout<<"\t\tYour choice :";
getline(cin,choice);
while (choice[0] !='1' && choice[0] !='2' &&choice[0] !='3' &&choice[0] !='4' &&choice[0] !='5' &&choice[0] !='6' &&choice[0] !='7' &&choice[0] !='8' &&choice[0] !='9' &&choice[0] !='0' )
{
cout<<"\n\t\t"<<choice<<" is invalid!";
cout<<"\n\t\tEnter correct choice: ";
getline(cin,choice);
}
cout<<"\n\t\t========================= \n\n";
}
//function
void engine(string &choice,Rec &J,fstream &infile,fstream &outfile,int SIZE,char fname[],char tname[])
{
switch (choice[0]){
case '1':
{
cout<<"Executing number "<<choice<<":"<<"Open/check file\n"<<endl;
openFile(fname);
break;
}
case '2':
{
cout<<"Executing number "<<choice<<":"<<"Add records\n"<<endl;
addRec(J,fname);
break;
}
case '3':
{
cout<<"Executing number "<<choice<<":"<<"Append records\n"<<endl;
appRec(J,outfile,fname);
break;
}
case '4':
{
cout<<"Executing number "<<choice<<":"<<"Search for a record\n"<<endl;
srcRec(J,infile,fname);
break;
}
case '5':
{
cout<<"Executing number "<<choice<<":"<<"Delete a record\n"<<endl;
delRec(J,infile, outfile,fname,tname);
break;
}
case '6':
{
cout<<"Executing number "<<choice<<":"<<"Delete all records\n"<<endl;
delAll(fname);
break;
}
case '7':
{
cout<<"Executing number "<<choice<<":"<<"Modify a record\n"<<endl;
modRec(J,outfile,fname);
break;
}
case '8':
{
cout<<"Executing number "<<choice<<":"<<"List all records\n"<<endl;
listAll(J,infile,fname);
break;
}
case '9':
{
cout<<"Executing number "<<choice<<":"<<"Sort all records\n"<<endl;
sort();
break;
}
default:exit(0);
}
}
//function
void openFile(char fname[])
{
cout<<"\nOpening file"<<fname<<"..."<<endl;
//confirm if file exists and opens
fstream infile;
fstream outfile;
infile.open(fname,ios::in|ios::binary);
if (infile.is_open())
{
cout<<"File "<<fname<<" exists, and was opened succesfully.";
}
infile.close();
//if fail ask to create
if (infile.fail())
{
cout<<"File does not exist. Create? [Y]/[N]";
char ch;
cin>>ch;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
//if yes then create file
if(ch=='y'|| ch=='Y')
outfile.open(fname,ios::out| ios::binary);
//if not created display error
if (outfile.fail())
{
cout<<"Error: File not created";
}
//else confirm creation of file
cout<<"File "<<fname<<" has been created.\n\n";
outfile.close();
}
}
//function
void addRec(Rec&J,char fname[])
{
fstream outfile;
outfile.open(fname,ios::out|ios::binary|ios::app);
char another[10];
do
{
cout<<"Please enter ID number :";
cin>>J.id;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout<<"\nPlease enter first name: ";
cin.getline(J.fname,SIZE);
cout<<"\nPlease enter lastname: ";
cin.getline(J.lname,SIZE);
outfile.write((char*) &J, sizeof(J));
cout<<"Add another record:[Y]/[N] ";
cin.get(another[0]);
cin.ignore(numeric_limits<streamsize>::max(), '\n');
} while(another[0]=='y'||another[0]=='Y');
cout<<"exiting to main menu.."<<endl;
}
//function
void delAll(char fname[])
{
fstream outfile;
cout<<"\n------------------\n"<<endl;
cout<<"\nDelete all records"<<fname<<"..."<<endl;
cout<<"\nAre you sure you want to delete all records in "<<fname<<" [Y]/[Any key for exit]?"<<endl;
char ch;
cin>>ch;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
if(ch=='y'||ch=='Y')
{
outfile.open(fname,ios::out|ios::binary|ios::trunc);
outfile.close();
}
else {cout<<"\nExiting to main menu..."<<endl;}
}
//function
void listAll(Rec&J,fstream &infile,char fname[])
{
infile.clear();
infile.open(fname,ios::in|ios::binary);
infile.read((char*)&J,sizeof(J));
cout<<"|=======================================================|"<<endl;
cout<<"| # | ID | FIRST | LAST |"<<endl;
cout<<"|=======================================================|"<<endl;
int count=1;
while(!infile.eof())
{
cout<<"| "<<setw(6)<<left<<count<<left<<"| "<<setw(9)<<J.id<<"| ";
cout<<left<<setw(14)<<J.fname<<"| ";
cout<<left<<setw(19)<<J.lname<<"|"<<endl;
infile.read((char*)&J,sizeof(J));
count=count+1;
cout<<"|-------------------------------------------------------|"<<endl;
}
infile.close();
}
//function
void appRec(Rec &J,fstream &outfile, char fname[])
{
outfile.open(fname,ios::out|ios::binary|ios::app);
outfile.clear();
cout<<"Please enter ID number :";
cin>>J.id;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout<<"\nPlease enter first name: ";
cin.getline(J.fname,SIZE);
cout<<"\nPlease enter lastname: ";
cin.getline(J.lname,SIZE);
outfile.write((char*) &J, sizeof(J));
outfile.close();
}
//----------------------------------------------------
void delRec(Rec&s,fstream &infile, fstream &outfile,char fname[],char tname[])
{
int current, request=1;
infile.open("c:/solident.dat",ios::in|ios::out|ios::binary);
if (!infile.is_open())
cout << "infile not open\n";
outfile.open("c:/temp.dat",ios::out|ios::binary|ios::trunc);
if (!outfile.is_open())
cout << "outfile not open\n";
for (;;)
{
infile.read((char*)&s, sizeof s);
if (infile.eof())
break;
current = s.id;
if (current != request)
outfile.write((char*)&s, sizeof s);
}
infile.close();
outfile.close();
infile.open("c:/temp.dat)",ios::in|ios::binary);
outfile.open("c:/solident.dat)", ios::out|ios::binary|ios::trunc);
for (;;)
{
infile.read((char*)&s, sizeof (s));
if (infile.eof())
break;
outfile.write((char*)&s, sizeof (s));
}
infile.close();
outfile.close();
}
void srcRec(Rec&Job,fstream &infile,char fname[])
{
cout << "Allowing the user to open a specific record.\n";
infile.open(fname, ios::in | ios::binary) ;
if(infile.fail())
{
cout << "Could not access file.\n";
}
else
{
int position; //user's position
//gets user's position
cout << "Please the record you would like to read: ";
cin >> position;
//ignore luki
cin.ignore(numeric_limits<streamsize>::max(), '\n');
//find the specific record, read it, and display it
infile.seekp((position - 1)*sizeof(Job));
infile.read((char*) &Job, sizeof(Job));
cout<<"|===============================================|"<<endl;
cout<<"| ID | FIRST | LAST |"<<endl;
cout<<"|===============================================|"<<endl;
cout<<left<<"| "<<setw(9)<<Job.id<<"| ";
cout<<left<<setw(14)<<Job.fname<<"| ";
cout<<left<<setw(19)<<Job.lname<<"|"<<endl;
}
//clears and closes the file
infile.clear();
infile.close();
}
void modRec(Rec &J,fstream &outfile, char fname[])
{
int position, //user's position
cntr = 0; //marks the current record within the file
cout << "Modifying a record.\n";
//open the two files
outfile.open(fname, ios::out | ios::in | ios::binary);
//get the user's desired position
cout << "please enter the record you would like to modify: ";
cin >> position;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << endl;
if(outfile.fail())
{
cout << "File could not be read.\n";
}
else
{
//find the desired record
outfile.seekp((position - 1)*(sizeof(J)));
//get the user's modification
cout<<"Please enter ID number :";
cin>>J.id;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout<<"\nPlease enter first name: ";
cin.getline(J.fname,SIZE);
cout<<"\nPlease enter lastname: ";
cin.getline(J.lname,SIZE);
//write over the desired record
outfile.write((char*) &J, sizeof(J));
}
//closes the files
outfile.close();
}
void sort()
{
int StructureSize, Idx1, Idx2;
FILE * binaryFile;
binaryFile = fopen("c:/solident.dat","rb+");
Rec Index, IndexTemp;
StructureSize = sizeof(Index);
fseek(binaryFile, 0, SEEK_END);
int fileSize = ftell(binaryFile);
rewind(binaryFile);
for (Idx1 = 0; Idx1 < fileSize; Idx1 += StructureSize)
{
for (Idx2 = 0; Idx2 < fileSize - StructureSize; Idx2 += StructureSize)
{
fread(&Index, StructureSize, 1, binaryFile);
fread(&IndexTemp, StructureSize, 1, binaryFile);
if (Index.id > IndexTemp.id)
{
fseek(binaryFile, -(StructureSize * 2), SEEK_CUR);
fwrite(&IndexTemp, StructureSize, 1, binaryFile);
fwrite(&Index, StructureSize, 1, binaryFile);
fseek(binaryFile, -StructureSize, SEEK_CUR);
}
else
{
fseek(binaryFile, -StructureSize, SEEK_CUR);
}
}
rewind(binaryFile);
}
fclose(binaryFile);
}
I don't know, there seem to be a few issues with this code. Here's just one of them though
int request=1,current;
...
while (!infile.eof())
{
s.id=current;
if (current!=request)
At no point in this code do you give current a value, but you are still using the variable. This is an uninitialised variable which is one reason your code isn't working.
I wonder if you meant to write
current=s.id;
instead? That would make a little more sense.
Try reading the file with a loop like this
infile.open("c:/solident.dat",ios::in|ios::out|ios::binary);
if (!infile.is_open())
cout << "infile not open\n";
outfile.open("c:/temp.dat",ios::out|ios::binary|ios::trunc);
if (!outfile.is_open())
cout << "outfile not open\n";
for (;;)
{
infile.read((char*)&s, sizeof s);
if (infile.eof())
break;
current = s.id;
if (current != request)
outfile.write((char*)&s, sizeof s);
}
infile.close();
outfile.close();
I wouldn't use fail() if I were you. I think it's extremely unlikely you'll detect a genuine read or write failure with it. It's much more likely to be an end of file error, or a failure to open a file.
#john .Thanks!
The first part works, but trying
rename(tempname,destination) does not work:
(the dest file exists)
Although the file temp.dat now contains the records minus the one deleted , the output is not written to the solident.dat file(it remains unchanged)
//So I tried to read every rec from file and write every record to dest file:
infile.open("c:/temp.dat)",ios::in|ios::binary);
outfile.open("c:/solident.dat)", ios::out|ios::binary|ios::trunc);
infile.read((char*)&s, sizeof s);
for (;;)
{
if (infile.eof())
break;
infile.read((char *)&s, sizeof (s));
outfile.write((char*)&s, sizeof (s));
}
infile.close();
outfile.close();
My understanding was, that outfile and infile are pretty straightforward: fstream.open, close , clear and it should work (I thought). It seems though that I'm missing something essential, because the simple delete binary struct function in the program seems to be a hit and miss and I've been going around in circles for a few days: parts of it work, then I add a few lines of code and either a function fails or the whole program fails.I tend to blame it on the compiler or devc++ :) but I'm certain it has to be the code that is invalid!
Thanks for help!