Deleting a record from a file in c++ - c++

I have wriiten a code to add , delete and dispaly a record of employees consisting of employee ID ,name,age and location.
But I am unable to code the delete function
My code is as follows:
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
class Document
{
public:
int Add();
void Delete();
void Display();
int No_of_lines();
int empno();
private:
fstream document;
fstream newdocument;
string data;
int age;
int emp_id;
int idtodelete;
char name[100],loc[100];
};
int Document::No_of_lines()
{
int number = 0;
document.open("document.txt");
while (getline(document, data))
{
++number;
}
return number;
}
int Document::Add()
{
Document d1;
document.open ( "document.txt",ios::app);
int x = d1.No_of_lines();
int emp_id = ++x;
cout << "The employee ID is: " << emp_id;
document <<emp_id;
cout<< "\n Ënter Name:" ;
cin>>name;
document <<"\t Name:"<< name;
cout<<"Enter Age:";
cin>> age;
document << "\t Age:"<< age;
cout<< "Enter location:";
cin>> loc;
document << "\t Location:"<< loc;
document << "\n";
document.close();
return 0;
}
void Document::Delete()
{
Document d2;
d2.Display();
int num;
char line[1000];
document.open("document.txt");
newdocument.open("newdocument.txt");
cout << "Enter the ID to delete \n";
cin >> idtodelete;
while (document.good())
{
const int maxchar = 1000;
const int maxtokens = 10;
char* token[maxtokens] = {};
char split[maxchar];
document.getline(split, maxchar);
int n = 0;
token[0] = strtok(split, " ");
istringstream(token[0]) >> num;
if (num != idtodelete)
{
document >> emp_id >> name >> age >> loc;
newdocument << emp_id<< name<< age<< loc;
}
else
{
}
}
document.close();
newdocument.close();
remove("document.txt");
rename("newdocument.txt", "document.txt");
}
void Document::Display()
{
document.open("document.txt");
while (!document.eof())
{
getline(document,data);
cout<<data<<endl;
}
document.close();
}
int main()
{
Document d;
char ans;
int ch;
do
{
system ( "cls");
cout<< "Enter your choice \n";
cout << "\t1. Add Data \n " << "\t2. Delete Data \n" << "\t3. Display Data \n";
cout<< "\t4. Exit\n";
cout<< " Enter Choice \n ";
cin >> ch;
switch(ch)
{
case 1:
cout << " Adding Data : \n";
d.Add();
break;
case 2:
//cout << "Deleting data : \n";
d.Delete();
break;
case 3:
cout << "Displaying data : \n";
d.Display();
break;
case 4:
cout << "Exit";
break;
default :
cout << "Invalid Input \n";
break;
}
cout<< " click y to quit or any other key to continue " ;
cin>>ans;
}
while (ans != 'y');
return 0;
}

The simple way is to remove by employee ID. You just ask for the employee ID, to know what employee to remove.
Then, you cannot remove lines in the middle of a sequential file, so you just
rename the file as document.back
create a new document.txt
read document.back and copy all employees to document.txt except the one you want to delete
close both files
remove document.back
That's all ... except for the usual test for IO errors, backup file existing, and so on...
I tested your code. First, you forgot to close document in method int Document::No_of_lines(). Next on my MSVC2008, I have to explicitely call document.clear() after reaching end of file. You also do not test document immediately after a getline, meaning that you execute the code after a bad read.
I removed newdocument from Document class, because IMHO it is useless. Here is a possible implementation of Delete:
void Document::Delete()
{
Document d2;
Display();
int num;
document.open("document.txt");
document.clear();
d2.document.open("newdocument.txt", ios::out | ios::trunc);
cout << "Enter the ID to delete \n";
cin >> idtodelete;
while (document.good())
{
getline(document, data);
if (document) {
int n = 0;
istringstream(data) >> num;
if (num != idtodelete)
{
d2.document << data << endl;
}
}
}
document.close();
d2.document.close();
remove("document.txt");
rename("newdocument.txt", "document.txt");
}

Related

Dealing with file io in c++

I have a program that takes input for names and outputs the last names in a string. The task I have now is to include FileIO in it. Specifically, "get user input for the filename, and then read the names from the file and form the last name string."
When I run the program, the console will show the name string from the text file. But only initially. As you keep entering names, that string disappears. Also, my user input for file name seems to be doing nothing, because I can enter anything and it still show the string of last names from the text file.
Here is what I have so far. Included all of it, just to make sure.
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <fstream>
using namespace std;
// function declerations
int Menu();
void getName(vector<string> &names, int &count);
void displayName(vector<string> &names, int count);
string getLastNames(vector<string> &names, int count);
int main()
{
vector<string> names;
int count = 0;
int choice = Menu();
ifstream File;
string line;
cout << "Enter file name: ";
getline(cin,line);
File.open("File.txt");
while(File.good()){
getline(File,line);
cout << line << endl;
}
File.close();
while (choice != 0)
{
// switch statement to call functions based on users input
switch (choice)
{
case 1: {
getName(names, count);
} break;
case 2: { displayName(names, count); } break;
case 3: {
cout << getLastNames(names, count) << endl;
} break;
case 0: {
return 0;
} break;
}
choice = Menu();
}
return 0;
}
// function definition for vector of strings
void getName(vector<string> &names, int &count)
{
string name;
// get input for name
cout << "Enter name: ";
getline(cin, name);
// find position of space in string
int pos = name.find(' ');
// reverse order of name
if(pos != -1) {
string first = name.substr(0, pos);
string last = name.substr(pos+1);
name = last + "," + first;
}
// add name to end of vector
names.push_back(name);
count++;
}
// give user option of what to do
int Menu() {
int choice;
cout << "1. Add a name" << endl;
cout << "2. Display names " << endl;
cout << "3. Show all Last Names" << endl;
cout << "0. Quit" << endl;
cout << "Enter a option: ";
cin >> choice;
// if outside of above choices, print 'choice not on list'
while (choice < 0 || choice > 3)
{
cout << "Choice not on list: ";
cin >> choice;
}
cin.ignore();
return choice;
}
// defining function that gets last names
string getLastNames(vector<string> &names, int count) {
stringstream ss;
for (int i = 0; i<count; i++)
{
int pos = names[i].find(',');
if (pos != -1) {
ss << "\"" << names[i].substr(0, pos) << "\", ";
} else {
ss << "\"" << names[i] << "\", ";
}
}
return ss.str();
}
// display the names
void displayName(vector<string> &names, int count)
{
if (count == 0)
{
cout << "No names to display" << endl;
return;
}
for (int i = 0; i<count; i++)
{
cout << names[i] << endl;
}
}

My function don't take over the variable value from other function

I have a program to create a phone book in a file. Some of my functions don't work or don't work properly.
user.h
#pragma once
#include <string>
#include <vector>
using namespace std;
class User
{private:
string firstname, lastname, country, city, street;
string phone;
public:
string prefix;
void ReadAllUsers(User[], int&);
void SaveUser(User, int&);
void SaveToFile(const User[], int);
void AddName(User[], int&);
void ListAllUsers(const User[], int&);
void Prefix(User, int);
void ChangePhone(User[], int&);
void Help();
void DeleteUser(User[], int&);
bool Search(string x)
{
return (phone.find(x) != string::npos);
}
};
user.cpp
#include "User.h"
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#pragma warning(disable:4996)
using namespace std;
const string PHONEBOOK_FILENAME = "phonebook.txt";
void User::Help()
{cout<<"\nWELCOME TO THE APPLICATION!\n";
cout<<"Press 0 to display on the screen all records that are saved in the file(phonebook.txt)\n";
cout<<"Press 1 to add 1 or more new record(s) in file(phonebook.txt)\n";
cout<<"Press 2 to delete permanently a record from file(phonebook.txt)\n";
cout<<"Press 3 to sort users from file(phonebook.txt) by name and display them on the screen\n";
cout<<"Press 4 to edit a user phone number and save it after in file(phonebook.txt)\n";
cout<<"Press 5 for help\n";
cout<<"Press 6 to exit the application\n";
}
void User::ReadAllUsers(User people[], int &num_people)
{
ifstream f;
f.open(PHONEBOOK_FILENAME.c_str());
if (f.fail())
{
cout << "Unable to open file " << endl;
return ;
}
int i = 0;
while (!f.eof() && i < 100)
{ getline(f, people[i].firstname);
getline(f, people[i].lastname);
getline(f, people[i].phone);
getline(f, people[i].country);
getline(f, people[i].city);
getline(f, people[i].street);
i++;
}
num_people = i;
f.close();
}
//Add country prefix to the phone number
void User::Prefix(User person, int num_people)
{string filecountry;
ifstream f;
f.open("prefix.txt");
{
while (getline(f, filecountry))
{
if (person.country == filecountry )
{
f.ignore();//next line
f >> person.prefix;
}
}
f.close();
}
}
void User::SaveUser(User person, int &num_people)
{
ofstream f(PHONEBOOK_FILENAME.c_str(), ios::app ) ;
if (f.fail())
cout << "Unable to open file " << endl;
else
f << person.firstname << " " << person.lastname << " " << person.country << " " << person.city << " " << person.street << " " << person.prefix << "-" << person.phone << endl;
cout << "\nThe user was added\n";
}
//Save data after a modification or after a user delete
void User::SaveToFile(const User people[], int num_people)
{ofstream f;
f.open(PHONEBOOK_FILENAME.c_str());
for(int i = 0; i < num_people; i++)
{
f << people[i].firstname << " " << people[i].lastname << " " << people[i].country << " " << people[i].city << " " << people[i].street << " " << people[i].prefix << " " << people[i].phone << endl;
}
}
// Read user data from the keyboard, add a new contact to the array
void User::AddName(User people[],int &num_people)
{User person;
cout <<"Enter the user's first name: ";
cin >> person.firstname;
cout <<"Enter the user's last name: ";
cin >> person.lastname;
cout <<"Enter the user's country: ";
cin >> person.country;
cout <<"Enter the user's city: ";
cin >> person.city;
cout <<"Enter the user's street: ";
cin >> person.street;
cout <<"Enter the user's phone number: ";
cin >> person.phone;
Prefix(person, num_people);
cout <<"The prefix is " << person.prefix;
for(int i = 0; i < num_people; i++)
{
if( i + 1 == num_people)
people[num_people] = person;
}
SaveUser(person, num_people);
num_people++;
}
// Ask the for person's name to change, find the person in the array and
// change it to the new phone number. Then save the new data to file by
// calling SaveToFile.
void User::ChangePhone(User people[], int &num_people)
{
User person;
int count;
cout <<"Enter name to change: ";
cin >> person.firstname;
for(count = 0; count < num_people; count++)
{
if(people[count].Search(person.firstname))
{ cout <<endl<< people[count].firstname<<endl;
cout <<"Current number"<<people[count].phone;
cout << "\nNew number: ";
cin >> people[count].phone;
SaveToFile(people,num_people);
cout <<"\n\nNew number Saved.";
return;
}
}
if(count = num_people)
cout <<"\nName not found.\n";
}
void User::DeleteUser(User people[], int &num_people)
{string phone;
int count = 0;
ifstream f;
f.open("phonebook.txt");
cout << "Input the phone of user that you want to delete ";
cin >> phone;
for(count = 0; count < num_people; count++)
{
if(people[count].Search(phone))
{ cout <<endl<< people[count].phone<<endl;
people[count].firstname = people[count].lastname = people[count].phone = people[count].country = people[count].city = people[count].street = " ";
}
SaveToFile(people,num_people);
cout <<"\n\nUser deleted.";
return;}
f.close();
}
The function Prefix()(this is to add automatically a country prefix for phone number, this is read from a file) is working but the value of person.prefix it's not taken by SaveUser(), so the value is not wrote in file.The function SaveToFile() save all users on single line in file.
And functions ChangePhone() and DeleteUser don't working.
The problem is that void User::Prefix(User person, int num_people) takes person by value, so it makes a copy of the person, changes the copy, then the copy goes away when the function ends. The original was never changed.
Instead, you want:
void User::Prefix(User & person, int num_people)
To have a reference to the person specified, which will be affected by the changes you make inside the function.
Also, I recommend you change your saveuser to be:
void User::SaveUser(User const & person, int &num_people) const
just to avoid making extra copies of the User object, but it's not incorrect the way you currently have it, I don't think.

Having an issue with my switch menu in a while loop

So I am working on a switch inside of a while loop. And it is not behaving properly. When I select 'l' and load the file it lets me select again, then when I try and press 'p' to print it, it just keeps looping over the selection prompt. I am pretty sure it is because choice != 'q', but don't know how to fix it.
Thank you for any help.
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
using namespace std;
//create a struct called Weather
struct Weather {
int month;
int date;
int high;
int avg;
int low;
double precip;
string event;
};
//function prototypes
int loadData(ifstream &file, Weather days[1000]);
void printData(Weather days[1000], int count);
int main() {
// declare variables
Weather days[1000];
ifstream inFile;
string checker;
char choice = '0';
int month = 0, count;
string path;
cout << "Welcome to the weather analyzer!" << endl;
while (choice != 'q') {
cout << "Would you like to (l)oad data, (p)rint data, (s)earch data, (o)rder the data, or (q)uit? ";
cin >> choice;
cout << endl;
switch (choice) {
case 'l':
// promt user for file path
cout << "Please enter the file path: ";
cin >> path;
// open the file
inFile.open(path);
// checks to see if file successfully opened and terminates if not
if (!inFile) {
cout << "Bad Path";
getchar();
getchar();
return 0;
}
loadData(inFile, days);
count = loadData(inFile, days);
break;
case 'p':
printData(days, count);
break;
case 's':
case 'o':
case 'q':
cout << "Good bye!";
break;
default:
cout << "Invalid option";
}
}
// Close file.
inFile.close();
// Pause and exit.
getchar();
getchar();
return 0;
}
//loading function
int loadData(ifstream &inFile, Weather days[1000]) {
string checker;
int month = 0;
int i; //i varaiable keeps track of how many lines there are for the print function
for (i = 0; !inFile.eof(); i++) {
inFile >> days[i].date; // gets date and checks if it is 2017 with if loop
if (days[i].date == 2017) {
getline(inFile, checker);
getline(inFile, checker);
inFile >> days[i].date; //gets correct date value
month++;//increments month counter
}
days[i].month = month;//gets and stores data from file into days
inFile >> days[i].high
>> days[i].avg
>> days[i].low
>> days[i].precip;
getline(inFile, days[i].event);
}
return i; //returns amount of days
}
// printing function
void printData(Weather days[1000], int count) {
for (int i = 0; i < count; i++) {
cout << days[i].month << " "
<< days[i].date << " "
<< days[i].high << " "
<< days[i].avg << " "
<< days[i].low << " "
<< days[i].precip << " "
<< days[i].event << " ";
cout << endl;
}
}
After reading the user input with cin, you probably want to flush the cin buffer:
cin.clear();
cin.ignore(INT_MAX);

How to alphabetize a list on C++

I have been having some trouble on my code for my final project. I have looked everwhere and I am having a hard time so I thought I would ask on here. I need to make sure that when all the names are listed in this phonebook that they will come out in alphabetical order but as of yet I am unsure how to do that. Here is the program that i currently have! Thank you!
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
using namespace std;
struct Contact {
string name, number, notes;
};
Contact contactList[100];
int rec_num = 0;
int num_entries;
string toUpper (string S) {
for (int i= 0; i < S.length(); i++)
S[i] = toupper(S[i]);
return S;
}
void ReadFile () {
string S;
fstream input("PhoneData.txt");
while (!input.eof() && !input.fail()){
input >> contactList[rec_num].name >> contactList[rec_num].number;
getline(input, S);
contactList[rec_num].notes = S;
rec_num++;
}
cout << "Book read." << endl;
num_entries = rec_num;
input.close();
return;
}
// stores phonebook for future runs of the program
void StoreFile () {
fstream F ("PhoneData.txt");
rec_num = 0;
while (rec_num < num_entries){
F << contactList[rec_num].name << " " << contactList[rec_num].number << " " << contactList[rec_num].notes << " " << endl;
rec_num++;
}
cout << "Phonebook stored." << endl;
return;
}
// adds contact
void add_name(string name, string number, string notes){
contactList[num_entries].name = name;
contactList[num_entries].number = number;
contactList[num_entries].notes = notes;
num_entries++;
return;
}
// finds contact
void retrieve_name(string name){
for (int i = 0; i < num_entries; i++){
if (toUpper(contactList[i].name) == toUpper(name)) {
cout << "Phone Number: " << contactList[i].number << endl << "Notes: " << contactList[i].notes << endl;
return;
}
}
cout << "Name not found" << endl;
return;
}
// updates contact info
void update_name(string name){
string new_number;
string new_notes;
cout<<"New Phone Number"<<endl;
cin>> new_number;
cout<<"New Notes"<<endl;
cin>> new_notes;
for (int i = 0; i < num_entries; i++){
if (toUpper(contactList[i].name) == toUpper(name)) {
contactList[i].number = new_number;
contactList[i].notes = new_notes;
return;
}
}
}
// deletes contact
void delete_name(string name){
int INDEX=0;
for (int i = 0; i < num_entries; i++){
if (toUpper(contactList[i].name) == toUpper(name)) {
INDEX=i;
for ( int j=INDEX; j < num_entries; j++ ){
contactList[j].name = contactList[j+1].name;
contactList[j].number = contactList[j+1].number;
contactList[j].notes = contactList[j+1].notes;
}
}
}
return;
}
void listAllContacts() {
int i = 0;
while (i < num_entries) {
cout << "-- " << contactList[i].name << " " << contactList[i].number << endl << "-- " << contactList[i].notes << endl << endl;
i++;
}
}
int main(){
string name, number, notes;
string FileName;
char command;
FileName = "PhoneData.txt";
ReadFile ();
cout << "Use \"e\" for enter, \"f\" for find, \"l\" for list, \"d\" for delete, \"u\" for update, \"s\" for send message, \"q\" to quit." << endl << "Command: ";
cin >> command;
while (command != 'q'){
switch (command){
case 'e': cin >> name; cout << "Enter Number: ";
cin >> number; cout << "Enter Notes: ";
cin.ignore(); getline(cin, notes);
add_name(name, number, notes); break;
case 'f': cin >> name; retrieve_name(name); break;
case 'l':
listAllContacts(); break;
case 'u': cin>> name; update_name (name);break;
case 'd' : cin>> name; delete_name (name); break;
}
cout << "\nCommand: "; cin >> command;
}
StoreFile();
cout << "All set !";
return 0;
}
Given
Contact contactList[100];
int num_entries;
you can use std::sort to sort the list of contacts. std::sort has two forms. In the first form, you can use:
std::sort(contanctList, contactList+num_entries);
if you define operator< for Contact objects.
In the second form, you can use:
std::sort(contanctList, contactList+num_entries, myCompare);
if you define myCompare to be callable object that can compare two Contact objects.
To use the first form, change Contact to:
struct Contact {
string name, number, notes;
bool operator<(Contact const& rhs) const
{
return (this->name < rhs.name);
}
};
If you want to the comparison of names to be case insensitive, convert both names to either uppercase or lowercase and them compare them.

Bank System not working

For some reason my bank script isn't working. More specifically, the search() does not work. I kind of understand why it doesn't, probably because of if(obj.returnId() == n), but I have no clue how to fix it. When I search an account, it will only allow me to find the last account made, not any of the previous ones. Here is my code:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <string.h>
#include <fstream>
#include <Windows.h>
#include <conio.h>
using namespace std;
bool loop = true;
class account
{
int id;
char name[40];
char password[40];
public:
void getData()
{
cout << "\nEnter your name: ";
cin >> name;
cout << "\nEnter ID: ";
cin >> id;
cout << "\Enter pass: ";
cin >> password;
}
void showData()
{
cout << "\nName: ";
puts(name);
cout << "\nID: " << id;
cout << "\n";
}
int returnId()
{
return id;
}
};
void createAccount()
{
account obj;
ofstream fileCreate;
fileCreate.open("accounts.dat", ios::binary|ios::app);
obj.getData();
fileCreate.write((char*)&obj,sizeof(obj));
fileCreate.close();
}
void display()
{
account obj;
ifstream fileRead;
fileRead.open("accounts.dat", ios::binary);
while(fileRead.read((char*)&obj, sizeof(obj)))
{
obj.showData();
}
fileRead.close();
}
void search(int n)
{
account obj;
ifstream fileRead;
fileRead.open("accounts.dat", ios::binary);
while(fileRead.read((char *) &obj, sizeof(obj)) );
{
fileRead.seekg(0,ios::beg);
if(obj.returnId() == n)
{
obj.showData();
}
else {
cout << "\nUser not foud!\n";
}
}
fileRead.close();
}
void main()
{
cout << "Welcome to the Bank.\n\n";
while (loop==true)
{
char choice[10];
cout << "Please select an option:\n";
cout << "------------------------------------------------\n";
cout << "(a)Log into an account\n(b)Create an account\n(s)Search an account\n(e)Exit\n";
cout << "------------------------------------------------\n";
cout << "Choice: ";
cin >> choice;
choice[0] = tolower(choice[0]);
cout << "\n------------------------------------------------\n\n";
switch (choice[0])
{
case 'a':
display();
break;
case 's':
int n;
cout << "Enter the ID of the account: ";
cin >> n;
search(n);
break;
case 'b':
createAccount();
break;
case 'e':
loop = false;
break;
default:
system("CLS");
cout << "The option \"" << choice[0] << "\" is invalid.\n\n\n\n";
break;
}
};
cout << "\n\n\n";
cout << "Click anything to exit.";
getch();
}
Your problem is the semicolon at the end of this line:
while(fileRead.read((char *) &obj, sizeof(obj)) );
That makes this loop have an empty body. So you basically read the whole file and throw away the results, except for the last entry.
get rid of this also:
fileRead.seekg(0,ios::beg);
I don't know why you need that, it would only make you read the first entry over and over.
The other error is that you should only say 'User not found' when you've tested all the accounts and they all failed. Your loop (when you've removed the semi-colon) is saying 'User not found' after every failed test.
You probably don't find the entry you are looking for because each time you have read an entry from the file, you reset the position to the beginning. This means that your loop will run forever, reading the same entry over and over again and never finding the entry you search for.
the seek might be the problem:
while(fileRead.read((char *) &obj, sizeof(obj)) ) //;
{
// seek to start?
//fileRead.seekg(0,ios::beg);
...
}
have a look at http://www.boost.org/doc/libs/1_51_0/libs/serialization/doc/index.html
aside, use
cout << "text" << endl;
for platform-agnostic newlines.