File Handling c++: using this pointer to read objects - c++

Is this correct?
Here Update is member function of Product class.
I am using this pointer(pointing to calling product object) to read objects stored in file over and over.
file.read((char *)this, sizeof(product));
Here if the class(see the update member function):
class product
{
int product_num;
string product_name;
int quantity;
float sell_p;
float buy_p;
int gst;
float total;
float profit;
public:
void calculate()
{
this->total = this->quantity * (this->sell_p);
this->profit = this->total - (this->buy_p * this->quantity) * (1 + this->gst / 100);
}
product()
{
product_num = 0;
product_name = "\0";
}
product(int p_num, string name, int quantity, float sell_p, float buy_p, int gst)
{
this->product_num = p_num;
this->product_name = name;
this->quantity = quantity;
this->sell_p = sell_p;
this->buy_p = buy_p;
this->gst = gst;
calculate();
}
void get_data()
{
cout << "Enter Serial Number: ";
cin >> this->product_num;
cout << "Enter Product Name(MAX LENGTH: 20): ";
cin>>this->product_name;
cout << "Enter Quantity: ";
cin >> this->quantity;
cout << "Enter Buying Price: ";
cin >> this->buy_p;
cout << "Enter GST: ";
cin >> this->gst;
cout << "Enter Selling Price: (Selling Price should be greater than " << (this->buy_p + (this->gst / 100) * this->buy_p) << " to turn profit)";
cin >> this->sell_p;
calculate();
}
void show_product()
{
cout << "Serial: " << this->product_num
<< "\nName: " << this->product_name
<< "\nQuantity: " << this->quantity
<< "\nSelling Price: " << this->sell_p
<< "\nBuying Price: " << this->buy_p
<< "\nGST: " << this->gst << endl;
}
bool remove_product(int x)
{
if (x > this->quantity)
return false;
this->quantity -= x;
return true;
}
int getSerialNumber()
{
return this->product_num;
}
string getName()
{
return this->product_name;
}
int getQuantity()
{
return this->quantity;
}
int getGST()
{
return this->gst;
}
float getTotal()
{
return this->total;
}
float getProfit()
{
return this->profit;
}
float getSellPrice()
{
return this->sell_p;
}
float getBuyPrice()
{
return this->buy_p;
}
bool isValid()
{
if (product_num == 0 || product_name == "\0")
return false;
return true;
}
void save()
{
ofstream fout;
fout.open("product.dat", ios::binary | ios::app);
if (!fout)
{
cout << "Failed To Open File!!\nExiting..";
exit(0);
}
else
{
fout.write((char *)this, sizeof(product));
}
fout.close();
}
void update()
{
int s_num = this->product_num;
fstream file;
file.open("product.dat", ios::binary | ios::ate | ios::in | ios::out);
if (!file)
{
cout << "Failed to open file!!!\nExiting...." << endl;
exit(0);
}
else
{
file.seekg(0);
file.read((char *)this, sizeof(product));
while (!file.eof())
{
if (s_num == this->product_num)
{
cout << "Product Detail: ";
this->show_product();
cout << "Enter the Values: " << endl;
cout << "Note: IF DONT WISH TO CHANGE KINDLY ENTER SAME VALUE.";
this->get_data();
file.seekp(-(sizeof(product)),ios::cur);
file.write((char *)this, sizeof(product));
break;
}
file.read((char *)this, sizeof(product));
}
}
file.close();
}
void remove_it()
{
int s_num = this->product_num;
ofstream fout;
ifstream fin;
fin.open("product.dat", ios::in | ios::binary);
if (!fin)
{
cout << "Failed to open file!!\nExiting...";
exit(0);
}
else
{
fout.open("temp.dat", ios::binary | ios::out);
fin.read((char *)this, sizeof(product));
while (!fin.eof())
{
if (!(s_num == this->product_num))
{
fout.write((char *)this, sizeof(product));
}
fin.read((char *)this, sizeof(product));
}
fin.close();
fout.close();
if(remove("product.dat") == 0)
cout<<"Sucessfully Deleted file\n";
else
cout<<"File Removal Failed\n";
if(rename("temp.dat", "product.dat") == 0)
cout<<"Successfully Renamed\n";
else
cout<<"Failed to Rename\n";
}
}
};

Related

Problem with file handling part of C++ assignment

This function is supposed to take care of updating the file after calling the respective functions for depositing or withdrawing from a user account. But it fails to do just that. I've checked as much as I can and all the other functions seem to be doing their jobs properly. I've traced it down to the specific lines where the program seems to fail.
int pos = (-1) * static_cast<int>(sizeof(ac));
File.seekp(pos, ios::cur);
//File.write((char *)&ac, sizeof(BankAccount));
File.write(reinterpret_cast<char *>(&ac), sizeof(BankAccount));
Yes, these are two versions of the line because I don't fully understand how either of them work. (First version is mine, second line is from a sample program we were given)
void makeDepositOrWithdraw(int option)
{
int num;
cout << "\nEnter account number: ";
cin >> num;
int amt;
bool found = false;
BankAccount ac;
SavingsAccount save;
fstream File;
File.open("Account.dat", ios::binary | ios::in | ios::out);
if (!File)
{
cout << "Cannot retrieve database right now. Try again later";
return;
}
while (!File.eof() && found == false)
{
File.read(reinterpret_cast<char *>(&ac), sizeof(BankAccount));
if (ac.getAccountNo() == num)
{
ac.displayAcc();
if (option == 1)
save.makeDeposit();
if (option == 2)
save.makeWithdrawal();
int pos = (-1) * static_cast<int>(sizeof(ac));
File.seekp(pos, ios::cur);
//File.write((char *)&ac, sizeof(BankAccount));
File.write(reinterpret_cast<char *>(&ac), sizeof(BankAccount));
cout << "__________________________________"
<< "\nRecord updated ";
found = true;
}
}
File.close();
if (!found)
cout << "Record not found";
}
EDIT: I'm sorry for being really bad at explaining this. The initial creation of a new account works. But trying to make additional deposit doesn't run into any error, the variables are being properly updated all the way up to the main BankAccount class. But nothing gets updated in the already existing account in the .dat file. Program still executes without any error.
I'm assuming if I understand the problem with the depositing part, I'll be able to solve the problem with withdrawing too, as both are handled in the same function.
#include <iostream>
#include <fstream>
#include <cctype>
#include <iomanip>
using namespace std;
class BankAccount
{
private:
float Balance, ServChargePerMonth, AnnualInterestRt, DepoAmt, WithdrwAmt;
int NoOfDepositPerMonth, NoOfWithdrawalPerMonth, AccountNo;
char Name[50], type;
public:
virtual void makeDeposit()
{
Balance += DepoAmt; //adding argument to acc bal
NoOfDepositPerMonth++; //incrementing noOfDeposit
};
virtual void makeWithdrawal()
{
Balance -= WithdrwAmt; //subtracting argument from acc bal
NoOfWithdrawalPerMonth++; //incrementing noOfWithdrawal
};
virtual void createAcc()
{
cout << "\nEnter your account number: ";
cin >> AccountNo;
cout << "\nEnter your full name: ";
cin.ignore();
cin.getline(Name, 50);
cout << "\nEnter the type of Account (C for current or S for savings): ";
cin >> type;
type = toupper(type);
cout << "\nEnter initial deposit amount: ";
cin >> Balance;
cout << "___________________________________________________________"
<< "\n\nAccount created." << endl;
};
void displayAcc()
{
cout << "\nAccount number: " << AccountNo
<< "\nAccount holder name: " << Name
<< "\nType of account: " << type
<< "\nAccount balance: $" << Balance
<< "\nTotal number of deposits: " << NoOfDepositPerMonth
<< "\nTotal number of withdrawals: " << NoOfWithdrawalPerMonth
<< "\nService Charge: $" << ServChargePerMonth << endl;
};
//getters
float getBalance() { return Balance; }
float getDepoAmt() { return DepoAmt; }
int getNoOfDeposit() { return NoOfDepositPerMonth; }
int getNoOfWithdraw() { return NoOfWithdrawalPerMonth; }
int getAccountNo() { return AccountNo; }
//setters
void setServChargePerMonth(float servCharge) //note: increasing, not setting
{
ServChargePerMonth += servCharge;
}
void setWithdrawAmt(float Amount)
{
WithdrwAmt = Amount;
}
void setBalance(float blnce)
{
Balance = blnce;
}
void setDepoAmt(float Amount)
{
DepoAmt = Amount;
}
};
class CheckingAccount : public BankAccount
{
public:
void makeWithdrawal(float WithdrwAmt)
{
if ((BankAccount::getBalance() - WithdrwAmt) < 0) //note: float doens't go below 0
setBalance(getBalance() - 15.0); //deducting $15
else
BankAccount::setWithdrawAmt(WithdrwAmt);
BankAccount::makeWithdrawal();
}
};
class SavingsAccount : public BankAccount
{
private:
bool statusVar;
bool status()
{
if (getBalance() < 25.0)
statusVar = false;
else
statusVar = true;
return statusVar;
}
public:
//setter
void setStatus(bool statusVar)
{
statusVar = status();
}
bool getStatus() { return statusVar; }
void makeWithdrawal()
{
if (status()) //check if active
{
cout << "Enter the amount you would like to withdraw today: ";
float WithdrwAmt;
cin >> WithdrwAmt;
CheckingAccount temp;
temp.makeWithdrawal(WithdrwAmt); //perform the reqd. check, as well as call the base ver.
}
else
{
cout << "Your account has deactivated. Please increase "
<< "your balance to reactivate your account.";
}
}
void makeDeposit()
{
cout << "Enter the amount you would like to deposit today: ";
float temp;
cin >> temp;
setDepoAmt(temp); //setting value for amt of deposit
//check previous balance
if (!status()) //if <$25,
{ //reactivate the acc. if depoAmt brings bal to $25
if ((getBalance() + getDepoAmt()) >= 25.0)
setStatus(true);
}
//check
BankAccount::makeDeposit(); //and then call the base ver.
}
};
void createAcc()
{
BankAccount ac;
ofstream writeFile;
writeFile.open("Account.dat", ios::binary | ios::app);
ac.createAcc();
writeFile.write(reinterpret_cast<char *>(&ac), sizeof(BankAccount));
writeFile.close();
}
void makeDepositOrWithdraw(int option)
{
int num;
cout << "\nEnter account number: ";
cin >> num;
int amt;
bool found = false;
BankAccount ac;
SavingsAccount save;
fstream File;
File.open("Account.dat", ios::binary | ios::in | ios::out);
if (!File)
{
cout << "Cannot retrieve database right now. Try again later";
return;
}
while (!File.eof() && found == false)
{
File.read(reinterpret_cast<char *>(&ac), sizeof(BankAccount));
if (ac.getAccountNo() == num)
{
ac.displayAcc();
if (option == 1)
save.makeDeposit();
if (option == 2)
save.makeWithdrawal();
int pos = (-1) * static_cast<int>(sizeof(ac));
File.seekp(pos, ios::cur);
//File.write((char *)&ac, sizeof(BankAccount));
File.write(reinterpret_cast<char *>(&ac), sizeof(BankAccount));
cout << "__________________________________"
<< "\nRecord updated ";
found = true;
}
}
File.close();
if (!found)
cout << "Record not found";
}
void display()
{
int num;
cout << "\nEnter account number: ";
cin >> num;
bool flag = false;
BankAccount ac;
ifstream inFile;
inFile.open("Account.dat", ios::binary);
if (!inFile)
{
cout << "Cannot retrieve database right now. Try again later";
return;
}
cout << "\nBALANCE DETAILS\n";
while (inFile.read(reinterpret_cast<char *>(&ac), sizeof(BankAccount)))
{
if (ac.getAccountNo() == num)
{
ac.displayAcc();
flag = true;
}
}
inFile.close();
if (!flag)
cout << "\nAccount number does not exist";
}
void deleteAcc()
{
int num;
cout << "\nEnter account number: ";
cin >> num;
BankAccount ac;
ifstream inFile;
ofstream outFile;
inFile.open("Account.dat", ios::binary);
if (!inFile)
{
cout << "Cannot retrieve database right now. Try again later";
return;
}
outFile.open("temp.dat", ios::binary);
inFile.seekg(0, ios::beg);
while (inFile.read(reinterpret_cast<char *>(&ac), sizeof(BankAccount)))
{
if (ac.getAccountNo() != num)
{
outFile.write(reinterpret_cast<char *>(&ac), sizeof(BankAccount));
}
}
inFile.close();
outFile.close();
remove("Account.dat");
rename("temp.dat", "Account.dat");
cout << "__________________________________________"
<< "Your account has been closed.";
}
int main()
{
char opt;
int temp;
start:
do
{
system("clear");
cout << "\n1. Create new account"
<< "\n2. Make a deposit"
<< "\n3. Make a withdrawal"
<< "\n4. Balance enquiry"
<< "\n5. Close existing account"
<< "\n6. Exit"
<< "\n\nPlease select your option(1-6)" << endl;
cin >> opt;
system("clear");
switch (opt)
{
case '1':
createAcc();
break;
case '2':
makeDepositOrWithdraw(1);
break;
case '3':
makeDepositOrWithdraw(2);
break;
case '4':
display();
break;
case '5':
deleteAcc();
break;
case '6':
cout << "Thank you for banking with us" << endl;
break;
default:
cout << "\a" << endl;
goto start;
break;
}
cin.ignore();
cin.get();
} while (opt != '6');
}
C++ places restrictions on the kind of objects you can use binary reads and writes on. They are complicated rules but the problem with your BankAccount object is that it has virtual functions and these mean you cannot use binary reads and writes.
Another problem is that you have several different kind of objects but your code reads and writes only BankAccount objects, not CheckingAccount objects or SavingsAccount objects.
So the code as written cannot work.
It's a common beginner mistake. Binary reads and writes are very limited in their functionality but beginners try to read and write all sorts of complex objects and expect it to just work, which it doesn't.
You need to redesign how you do the I/O in your program. I'm not sure what you requirements are but dropping the use of binary I/O seems the simplest way to proceed.

My programs works in Visual Studio but not in other IDE example AWS Cloud 9

I created my program in Visual Studio, it works perfectly the input / output etc. are all correct. When I run it in AWS Cloud 9 or Mirmir I get the same error message, What does this mean? How should I modify it to work in AWS? I thought C++ codes work in all IDE which supports C++. The errors are:
In constructor ‘Departments::Departments(int, char*, char*)’:
error: ‘strcpy_s’ was not declared in this scope
strcpy_s(Departmentname, nameOfDepartment);
^
In constructor ‘Employee::Employee(int, char*, double, double, int)’:
error: ‘strcpy_s’ was not declared in this scope
strcpy_s(emploeename, nameOfTheEmployee);
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
using namespace std;
const int SizeForString = 100;
char deptartmentRecordFileName[100] = "departments.dat ";
char employeeRecordFileName[100] = "employees.dat";
struct Departments {
int DepartmentID;
char Departmentname[SizeForString];
char DepartmentHeadName[SizeForString];
Departments()
{
}
Departments(int idOfTheDepartment, char nameOfDepartment[], char headNameOfDepartment[])
{
DepartmentID = idOfTheDepartment;
strcpy_s(Departmentname, nameOfDepartment);
strcpy_s(DepartmentHeadName, headNameOfDepartment);
}
};
struct Employee {
int employeeID;
char emploeename[SizeForString];
double employeesalary;
double employeeage;
int employeeDepartmentID;
Employee()
{
}
Employee(int idOfTheEmployee, char nameOfTheEmployee[], double salaryOfTheEmployee, double ageOfTheEmployee, int departmentId)
{
employeeID = idOfTheEmployee;
strcpy_s(emploeename, nameOfTheEmployee);
employeesalary = salaryOfTheEmployee;
employeeage = ageOfTheEmployee;
employeeDepartmentID = departmentId;
}
};
bool DepartmentIdCheck (int id)
{
Departments temp;
ifstream myfile1(deptartmentRecordFileName, ios::in | ios::binary | ios::app);
if (!myfile1)
{
cout << "Error To Open File.\n";
return false;
}
while (myfile1.read((char*)&temp, sizeof(Departments)))
{
if (temp.DepartmentID == id)
{
myfile1.close();
return true;
}
}
myfile1.close();
return false;
}
bool checkIDEmplyee (int id)
{
Employee temp;
ifstream myfile1(employeeRecordFileName, ios::in | ios::binary | ios::app);
if (!myfile1)
{
cout << "Error To Open File.\n";
return false;
}
while (myfile1.read((char*)&temp, sizeof(Employee)))
{
if (temp.employeeID == id)
{
myfile1.close();
return true;
}
}
myfile1.close();
return false;
}
void writeDepartmentData(Departments temp)
{
ofstream myfile1(deptartmentRecordFileName, ios::out | ios::binary | ios::app);
if (!myfile1)
{
cout << "Error To Open File.\n";
return;
}
myfile1.write((char*)&temp, sizeof(Departments));
myfile1.close();;
}
void writeEmployeeData(Employee temp)
{
ofstream myfile1(employeeRecordFileName, ios::out | ios::binary | ios::app);
if (!myfile1)
{
cout << "Error To Open File.\n";
return;
}
myfile1.write((char*)&temp, sizeof(Employee));
myfile1.close();
}
void createReport()
{
double totalSalary = 0;
Departments depTemp;
ifstream myfile1(deptartmentRecordFileName, ios::in | ios::binary | ios::app);
if (!myfile1)
{
cout << "Error To Open File.\n";
return;
}
while (myfile1.read((char*)&depTemp, sizeof(Departments)))
{
Employee empTemp;
ifstream myfile2(employeeRecordFileName, ios::in | ios::binary | ios::app);
while (myfile2.read((char*)&empTemp, sizeof(Employee)))
{
if (!myfile1)
{
cout << "Error To Open File.\n";
return;
}
if (depTemp.DepartmentID == empTemp.employeeDepartmentID)
{
totalSalary += empTemp.employeesalary;
}
}
cout << "Dept : " << depTemp.Departmentname << endl;
cout << "Total Salary : $" << totalSalary << endl << endl;
myfile2.close();
totalSalary = 0;
}
myfile1.close();
}
int main()
{
int choice = 0;
while (choice != 4)
{
cout << "\nHuman Resources Menu";
cout << "\n1. Create Department"
"\n2. Create Employee"
"\n3. Display Salary Report"
"\n4. -- Quit -- " << endl;
cout << "Please make a selection : ";
cin >> choice;
if (choice == 1)
{
int deptIdInput;
char nameDeptInput[SizeForString];
char headNameInput[SizeForString];
cout << "Please Enter Department Details:" << endl;
cout << "Department ID : ";
cin >> deptIdInput;
bool IdExit = DepartmentIdCheck (deptIdInput);
if (IdExit)
{
cout << "Value must be unique!" << endl;
continue;
}
cout << "Department Name : ";
cin >> nameDeptInput, SizeForString;
cout << "Head of Department : ";
cin >> headNameInput;
Departments d(deptIdInput, nameDeptInput, headNameInput);
writeDepartmentData(d);
}
else if (choice == 2)
{
int idEmploy;
char nameEmploy[SizeForString];
double salaryEmploy;
double ageEmploy;
int departmentIdForEmploy;
cout << "Please Enter Employee Details:" << endl;
cout << "Employee ID : ";
cin >> idEmploy;
bool IdExit = checkIDEmplyee (idEmploy);
if (IdExit)
{
cout << "Value must be unique !" << endl;
continue;
}
cout << "Employee Name : ";
cin >> nameEmploy;
cin.ignore();
cout << "Salary: $";
cin >> salaryEmploy;
cout << "Age : ";
cin >> ageEmploy;
cout << "Department ID : ";
cin >> departmentIdForEmploy;
bool foundId = DepartmentIdCheck (departmentIdForEmploy);
while (!foundId)
{
cout << "Please enter a valid department ID : ";
cin >> departmentIdForEmploy;
foundId = DepartmentIdCheck (departmentIdForEmploy);
}
Employee e(idEmploy, nameEmploy, salaryEmploy, ageEmploy, departmentIdForEmploy);
writeEmployeeData(e);
}
else if (choice == 3)
{
createReport();
}
else if (choice != 4)
{
cout << "Please enter a valid choice" << endl;
}
}
}
Your Visual Studio IDE may have loaded in libraries for you that your other IDEs do not. It looks like strcpy is part of the <cstring> library. You will need to #include <cstring> to use it.
Visual Studio runs on Windows while Cloud9 runs on linux. They use different compilers with different standard libraries.

fstream read and write functions errors

i am creating this program that stores some items into the (.dat) file..
the program seems to run smoothly but when i try to read the data from the file i see special character on my screen and none of the data that i was trying to save, was saved properly, note that when i run the similar code in main() it works and it actually shows me the correct output.. please help me on this i really don't know what to do here
void viewFile() {
Product item;
ifstream file("products.dat", ios::binary);
if (!file.read(reinterpret_cast<char*>(&item), sizeof(Product))) {
cout <<"failed to read";
system("exit");
}
item.viewProduct();
while (!file.eof()) {
item.viewProduct();
cout <<endl <<endl;
file.read((char *)(&item), sizeof(Product));
}
file.close();
}
void addProductToInventory() {
string name;
int quantity;
int pricePerItem;
ofstream obj("products.dat", ios::out | ios::binary);
Product item;
int numberOfProducts;
cout <<"enter the number of products you want to add in this inventory: ";
cin >> numberOfProducts;
for (int counter = 1; counter <= numberOfProducts; counter++) {
Product product;
cout <<"enter the name of the object: ";
cin >> name;
cout <<"enter the quantity of the product: ";
cin >> quantity;
cout <<"enter the price of this product (per item): ";
cin >> pricePerItem;
product.setName(name);
product.setQuantity(quantity);
product.setPricePerItem(pricePerItem);
if (!obj.write(reinterpret_cast<char*>(&product), sizeof(Product))) {
cout <<"failed writing\n";
system("exit");
}
cout <<"item added\n\n";
}
obj.flush();
obj.close();
}
this is my code in main() which WORKS its exactly the same code.. i guess
ofstream file ("products.dat", ios::out | ios::binary | ios::trunc);
Product p1("hammer", 12, 3);
Product p2("screw driver", 43, 1);
if (!file.write(reinterpret_cast<char*>(&p1), sizeof(Product))) {
cout <<"failed to write";
system("exit");
}
file.write(reinterpret_cast<char*>(&p2), sizeof(Product));
file.close();
ifstream file2("products.dat", ios::out | ios::binary);
if (!file2.read(reinterpret_cast<char*>(&p1), sizeof(Product))) {
cout <<"failed to read";
system("exit");
}
while (!file2.eof()) {
p1.viewProduct();
cout <<endl <<endl;
file2.read((char *)(&p1), sizeof(Product));
}
file2.close();
}
P.S i am really sorry if this comes out to be a messy question.. I have been debugging this for hours and now i can't even think straight.
Lets start by thinking about how pointers work.
char* a = new char[2];
a[0] = 'a';
a[1] = 'b';
char* b = a;
std::cout << a[0] << a[1]; //prints ab
std::cout << b[0] << b[1]; //prints ab
a[1] = 'c';
std::cout << b[0] << b[1]; //prints ac
delete[] a;
std::cout << b[0] << b[1]; //prints random garbage because the memory that b points at is deleted
know lets start writing these pointers to files
char* a = new char[2];
a[0] = 'a';
a[1] = 'b';
ofstream outFile("products.dat", ios::binary | ios::trunc);
outFile.write(reinterpret_cast<char*>(&a), sizeof(a));
outFile.close();
{
ifstream inFile("products.dat", ios::binary);
char* b;
inFile.read(reinterpret_cast<char*>(&b), sizeof(b));
std::cout << b[0] << b[1]; //prints ab
a[1] = 'c';
std::cout << b[0] << b[1]; //prints ac
}
delete[] a;
{
ifstream inFile("products.dat", ios::binary);
char* b;
inFile.read(reinterpret_cast<char*>(&b), sizeof(b));
std::cout << b[0] << b[1];//prints random garbage because the memory that b points at is deleted
}
std::string contains pointers to dynamically allocated memory.
You should do something like this.
void viewFile() {
ifstream file("products.dat", ios::binary);
while (!file.eof()) {
int nameLength = 0;
if (!file.read(reinterpret_cast<char*>(&nameLength), sizeof(nameLength))) {
cout <<"failed to read";
system("exit");
}
std::string name{ nameLength, '?' };
if (!file.read(name.data(), sizeof(char) * nameLength) {
cout <<"failed to read";
system("exit");
}
int quantity;
if (!file.read(reinterpret_cast<char*>(&quantity), sizeof(quantity)) {
cout <<"failed to read";
system("exit");
}
int pricePerItem;
if (!file.read(reinterpret_cast<char*>(&pricePerItem), sizeof(pricePerItem)) {
cout <<"failed to read";
system("exit");
}
Product item{ std::move(name),quantity, pricePerItem };
item.viewProduct();
}
file.close();
}
void addProductToInventory() {
string name;
int quantity;
int pricePerItem;
ofstream obj("products.dat", ios::out | ios::binary);
int numberOfProducts;
cout <<"enter the number of products you want to add in this inventory: ";
cin >> numberOfProducts;
for (int counter = 1; counter <= numberOfProducts; counter++) {
cout <<"enter the name of the object: ";
cin >> name;
cout <<"enter the quantity of the product: ";
cin >> quantity;
cout <<"enter the price of this product (per item): ";
cin >> pricePerItem;
int nameLength = name.size();
if (!obj.write(reinterpret_cast<char*>(&nameLength), sizeof(nameLength))) {
cout <<"failed writing\n";
system("exit");
}
if (!obj.write(name.data(), sizeof(char) * nameLength) {
cout <<"failed writing\n";
system("exit");
}
if (!obj.write(reinterpret_cast<char*>(&quantity), sizeof(quantity))) {
cout <<"failed writing\n";
system("exit");
}
if (!obj.write(reinterpret_cast<char*>(&pricePerItem), sizeof(pricePerItem))) {
cout <<"failed writing\n";
system("exit");
}
cout <<"item added\n\n";
}
obj.flush();
obj.close();
}

How to return index of item in .dat file?

How do I return the location of an item in a .dat file?
in the search() function I attempting to find an item in the fractions.dat file and return it to the user. However the function always returns -2 (the value that the variable being returned was initialized to originally).
The if statement executes, but it appears that file.read(...) isn't setting cur to anything.
#include <iostream>
#include <fstream>
using namespace std;
struct Fraction
{
int num, den;
};
int search(fstream& file, Fraction* f);
int menu();
void proccessChoice(int i);
Fraction* readFrac();
Fraction* fracs[100];
int index;
string fileName = "fractions.dat";
fstream file(fileName, ios::in | ios::out | ios::binary);
int main()
{
if (!file)
{
cout << "Error opening file. Program aborting.\n";
system("pause");
exit(1);
}
int choice;
do
{
choice = menu();
proccessChoice(choice);
} while(choice != 3);
system("pause");
return 0;
}
int menu()
{
int c;
cout << "1.Enter new fraction" << endl;
cout << "2.Find fraction location" << endl;
cout << "3.Quit" << endl;
cin >> c;
return c;
}
void proccessChoice(int i)
{
switch(i)
{
case 1:
{
cout << "Please enter a fraction to be stored: ";
fracs[index] = readFrac();
file.write(reinterpret_cast<char*>(fracs[index]), sizeof(Fraction));
/*cout << fracs[index]->num << "/" << fracs[index]->den ;*/
index++;
}
break;
case 2:
{
cout << "Please enter a fraction to find: ";
Fraction* fToFind = readFrac();
int i = search(file, fToFind);
cout << "The fraction is at position: "<< i << endl;
}
break;
}
}
int search(fstream& file, Fraction* f)
{
Fraction* cur = new Fraction();
int pos = -2;
if (!file)
{
cout << "Error opening file. Program aborting.\n";
system("pause");
exit(1);
}
while(!file.eof())
{
file.read(reinterpret_cast<char *>(cur), sizeof(Fraction));
if((cur->num == f->num) && (cur->den == f->den))
{
cout << "\nFrac found!" << cur->num << "/" << cur->num<<endl;
pos = file.tellg();
return pos;
}
}
return pos;
}
Fraction* readFrac()
{
Fraction* f = new Fraction();
char slash;
cin >> f->num >> slash >> f->den;
return f;
}
You're not starting the search from the beginning of the file. You need:
file.seekg( 0, std::ios::beg );
Similarly I think you're not appending to the end when writing to the file.
file.seekp( 0, std::ios::end );

Reading and writing to .dat file

Why does this file always contain an extra Fraction structure? If a user enters option 3 to view all fractions when the program just starts (the file should be empty), 0/0 is printed out. If a user selects option one and enters a fraction 1/1, and then selects option 3, two fractions are printed out 1/1 1/1.
Note: to run this you will need to create an empty .dat file called "fractions.dat"
I really appreciate your help!
#include <iostream>
#include <fstream>
using namespace std;
struct Fraction
{
int num, den;
};
int search(fstream& file, Fraction* f);
int menu();
void proccessChoice(int i);
Fraction* readFrac();
Fraction* fracs[100];
int index;
string fileName = "fractions.dat";
fstream file(fileName, ios::in | ios::out | ios::binary | ios::trunc);
//structure called Fraction with num and den as its only integer members
int main()
{
if (!file)
{
cout << "Error opening file. Program aborting.\n";
system("pause");
exit(1);
}
int choice;
do
{
choice = menu();
proccessChoice(choice);
} while(choice != 4);
system("pause");
return 0;
}
int menu()
{
int c;
cout << "1.Enter new fraction" << endl;
cout << "2.Display/update a fraction" << endl;
cout << "3.Display all fractions" << endl;
cout << "4.Quit" << endl;
cin >> c;
return c;
}
void proccessChoice(int i)
{
switch(i)
{
case 1:
{
cout << "Enter a fraction to add: ";
fracs[index] = readFrac();
file.seekp(0, ios::end);
file.write(reinterpret_cast<char*>(fracs[index]), sizeof(Fraction));
/*cout << fracs[index]->num << "/" << fracs[index]->den ;*/
index++;
}
break;
case 2:
{
cout << "Enter fraction to view/update: ";
Fraction* fToFind = readFrac();
int i = search(file, fToFind);
if (i == -1)
{
cout << "Fraction not found." << endl;
}
else
{
char r;
cout << fToFind->num << "/" << fToFind->den << " found at index " << i << ". Update? [y/n]";
cin >> r;
if(r == 'y' || r == 'Y')
{
cout << "Enter a new fraction: ";
Fraction* fToWrite = readFrac();
file.seekp(sizeof(Fraction) * (i));
file.write(reinterpret_cast<char*>(fToWrite), sizeof(Fraction));
}
}
cout << i << endl;
cout << "Case 2" << endl;
}
break;
case 3:
{
Fraction* cur = new Fraction();
//int pos = -1;
if (!file)
{
cout << "Error opening file. Program aborting.\n";
system("pause");
exit(1);
}
file.seekg(0, ios::beg);
while(!file.eof())
{
file.read(reinterpret_cast<char *>(cur), sizeof(Fraction));
cout << cur->num << "/" << cur->den << endl;
}
cout << "Case 3" << endl;
}
break;
}
}
int search(fstream& file, Fraction* f)
{
Fraction* cur = new Fraction();
int pos = -1;
if (!file)
{
cout << "Error opening file. Program aborting.\n";
system("pause");
exit(1);
}
file.seekg(0, ios::beg);
while(!file.eof())
{
file.read(reinterpret_cast<char *>(cur), sizeof(Fraction));
if((cur->num == f->num) && (cur->den == f->den))
{
cout << "\nFrac found!" << cur->num << "/" << cur->den<<endl;
pos = file.tellg()/sizeof(Fraction) - 1;
return pos;
}
}
return pos;
}
Fraction* readFrac()
{
Fraction* f = new Fraction();
char slash;
cin >> f->num >> slash >> f->den;
return f;
}
Attempted solution 1: works for the first attempt of the user to view all fractions but on the second attempt the file is not found.
case 3:
{
Fraction* cur = new Fraction();
//int pos = -1;
if (!file)
{
cout << "Error opening file. Program aborting.\n";
system("pause");
exit(1);
}
file.seekg(0, ios::beg);
while(!file.eof())
{
if(file.read(reinterpret_cast<char *>(cur), sizeof(Fraction)).gcount()== sizeof(Fraction))
{
cout << cur->num << "/" << cur->den << endl;
}
}
cout << "Case 3" << endl;
}
break;
}
Because you didn't yet reach the end of the file!
while(!file.eof())
You opened the empty file, however, note that the read cursor is currently at position 0. As long as you didn't attempt to read data file.eof() will be false, as the end of file hasn't been reached yet by the cursor.
You'll need to check whether you were actually able to extract the Fraction:
if(
file.read(reinterpret_cast<char *>(cur), sizeof(Fraction)).gcount()
== sizeof(Fraction)
){
// Fraction has been extracted
}
else
// either eof() or some other error.
Note that this gets much simpler if you provide a custom operator for this:
std::istream& operator>>(std:istream& in, Fraction& f){
return in.read(reinterpret_cast<char *>(&f), sizeof(Fraction));
}
// ....
while(file >> *cur){
// ... your code.
}