How to edit specific value in binary file? - c++

I have a structure of flight, which is being writing into binary file and i want to edit flight destination and i have no idea how to do it.
This is my code for getting user input and writting to binary file.
struct Flight_Details {
char destination[99];
char departure[99];
char time_depart[80];
char time_arrive[80];
int flight_number;
};
switch (menu)
{
case MENU::NEW_FLIGHT: {
Flight_Details flight_d;
cout << "Enter Departure: ";
cin >> flight_d.destination;
cout << "Enter Destination: ";
cin >> flight_d.departure;
cout << "Enter Departure Time: ";
cin >> flight_d.time_depart;
cout << "Please enter arriving time: ";
cin >> flight_d.time_arrive;
cout << "Flight Number: ";
cin >> flight_d.flight_number;
ofstream file;
file.open("Flgiht_Details.data", ios::binary);
if (!file) cout << "Could create/open file";
else {
file.write((char*)&flight_d, sizeof(flight_d));
file.close();
}
break;
}
case MENU::OUTPUT_FILE: {
ifstream readFile;
readFile.open("Flgiht_Details.data");
if (!readFile) cout << "Couldn't open file";
else {
readFile.seekg(0, ios::end);
int fileSize = readFile.tellg();
int countOfFlights = fileSize / sizeof(Flight_Details);
readFile.seekg(0, ios::beg);
Flight_Details* flight = new Flight_Details[countOfFlights];
readFile.read((char*)flight, countOfFlights *sizeof(Flight_Details));
readFile.close();
for (int i = 0; i < countOfFlights; i++)
{
cout << flight[i].destination << "\n" << flight[i].departure << "\n" << flight[i].time_depart << "\n" << flight[i].time_arrive << "\n" << flight[i].flight_number << "\n\n";
}
break;
}
}
case MENU::EDIT: {
Flight_Details* flight_d;
ifstream readFile;
readFile.open("Flgiht_Details.data");
if (!readFile) cout << "Couldn't open file";
else {
readFile.seekg(0, ios::end);
int fileSize = readFile.tellg();
int countOfFlights = fileSize / sizeof(Flight_Details);
readFile.seekg(0, ios::beg);
Flight_Details* flight = new Flight_Details[countOfFlights];
readFile.read((char*)flight, countOfFlights * sizeof(Flight_Details));
readFile.close();
ofstream file;
char edit[50];
cout << "Edit: ";
cin.getline(edit, 50);
for (int i = 0; i < countOfFlights; i++)
{
if (strcmp(flight_d[i].destination, edit) == 0)
{
//edit file
}
}
}
}
}

Since your Flight_Details has a fixed size in bytes when written, it is easy to calculate where in the file each flight is. The general equation is flight_number * sizeof(Flight_Details)//where flight_number is 0..N. This will calculate a byte offset into the file to seek to. From there it is just a matter of reading exactly sizeof(Flight_Details) bytes from the file and converting that buffer into a Flight_Details which in this case could mean that you just fill each buffer in the Flight_Details with the bytes manually, or if you prefer you could just reinterpret_cast() the char* of data into the right type(this will only be a decent idea if your buffer is exactly sizeof(Flight_Details) long. It would be safer to just manually copy the bytes in via a constructor of some kind.

Here is what you will write under // edit file comment. This looks ugly but it works pretty fine
cout << "Yeah we are editing\n";
char newdestiny[99];
cout << "new dest: ";
cin.getline(newdestiny, 99);
strcpy(flight[i].destination, newdestiny);
file.write((char*)flight, sizeof(Flight_Details[countOfFlights]));
file.close();
return 0;
and you have got bugs in your program like when you ask for desparture you are getting destination and when you open file for writing that data you have to include ios::app flag so you can enter new flight information as well(?)
the file I am opening has only ios::out flag
and one more thing strcmp(flight_d[i].destination, edit) == 0 line should be strcmp(flight[i].destination, edit) == 0

Related

Writing to txt file C++

I would like to write the words in the file until I type the word "stop", but only the first word is saved to the file.
What's the problem?
int main(int i)
{
ofstream file;
string file_name,message;
cout << "\nFilename: ";
cin >> file_name;
cout << "Write 'stop' to end writig to file" << endl;
for(i=0; message!="stop"; i++)
{
cout << "\nYour message: ";
cin >> message;
file.open(file_name.c_str());
file << message.c_str() << "\t" ;
}
file.close();
return 0;
}
It should be,
int main()
{
int i;
ofstream file;
string file_name,message;
cout << "\nFilename: ";
cin >> file_name;
cout << "Write 'stop' to end writig to file" << endl;
file.open(file_name.c_str());
for(i=0; message!="stop"; i++)
{
cout << "\nYour message: ";
cin >> message;
if(message == "stop"){ //If you dont want word stop
break;
}
file << message.c_str() << "\t" ;
}
file.close();
return 0;
}
It would be better if you do something like,
do{
//do stuff
if (message == "stop")
break;
}while(message != "stop");
In this case, you better switch to a while loop of the form: while (!file.eof()), or while (file.good()).
Apart from that, the for loop has to define the variable, in your case i is undefined, and must contain the range of the variable and no other variable definition (condition on message must not be inside it. It has to be an if condition inside the for loop).
...
char word[20]; // creates the buffer in which cin writes
while (file.good() ) {
cin >> word;
if (word == "stop") {
break;
...
}
}
...
Actually, I am not sure how it compiles at all in your case :) For future reference: for loop should look like this: for (int i = 0; i<100; i++) {};
I hope it is clear!

Can't read class objects from a file while using vector in c++

I'm learning C++ and I'm creating a simple C++ code in visual studio 2017 community. When the program read objects from a file then vs2017 gives an exception thrown.So how to solve this guys.
fstream File; Company Temp; try{ vector<Company>Object; // Company class name
cout << " 1. Show Data ";
cout << " 2. Put Data\n";
cout << " => ";
int a; cin >> a; cin.ignore(1000, '\n');
if (a == 1)
throw 5;
Temp.Get_Data();
Object.push_back(Temp);
File.open("Ma.bin", ios::binary | ios::out | ios::app);
int i = 0;
for (vector<Company>::iterator It = Object.begin(); It != Object.end(); It++) {
File.write((char *)&Object[i], sizeof(Object[i]));
i++;
}
File.close();
}
catch (int) {
Object.clear();
File.open("Ma.bin", ios::binary | ios::in);
File.seekg(0, ios::end);
auto total = File.tellg() / sizeof(Company);
cout << " total Object write " << total << "\n";
cout << " Which One you want to Dispaly ?"; int Number; cin >> Number; cin.ignore(1000, '\n');
int Position = (Number - 1) * sizeof(Company);
File.seekg(Position);
File.read((char *)&Temp, sizeof(Temp)); //this is the bug , if i comment this line then programme runs ok
Object.push_back(Temp);
File.close();
vector<Company>::iterator It = Object.begin();
It->Put_Data();
}
return 0;
}

My code isn't overwriting the text file, even though it should be?

We did a very similar type of code in C++ class but my version isn't working right, even though it is line-by-line (almost) the same.
My code is meant to save a user's Pokemon and they can add and delete as they please. My display function is working but my add and delete function are not. All the files are opening, but it's not overwriting the file like it's supposed to. Really unsure of what to do, I'm very much a beginner and I don't know much.
Here is what I've got so far:
string name[100];
string type[100];
int level[100];
string newPokemon;
string newType;
int newLevel;
ifstream fin;
ofstream fout;
int numberOfPokemon = 0;
//Input Pokemon Info
cout << "Name of Pokemon: ";
getline(cin, newPokemon);
cin.ignore(100, '\n');
cout << "Pokemon type: ";
getline(cin, newType);
cin.ignore(100, '\n');
cout << "Pokemon level: "; //weird gap between "Pokemon type" and "pokemon level". I have to press enter twice from "pokemon type" to get to "pokemon level"
cin >> newLevel;
cin.ignore(5, '\n');
fin.open("pokemon.txt");
//Put file in array
if (fin.is_open())
{
while (isalnum(fin.peek()) && numberOfPokemon < 100)
{
getline(fin, name[numberOfPokemon]);
getline(fin, type[numberOfPokemon]);
fin >> level[numberOfPokemon];
fin.ignore(100, '\n');
if (name[numberOfPokemon] != newPokemon)
numberOfPokemon++;
}
fin.close();
}
//Output file
fout.open("pokemon.txt");
if (fout.is_open())
{
for (int i = 0; i < numberOfPokemon; i++)
{
fout << name[i] << "\n";
fout << type[i] << "\n";
fout << level[i] << "\n";
}
//Tack on new piece
fout << newPokemon << "\n";
fout << newType << "\n";
fout << newLevel << "\n";
fout.close();
cout << "Add Successful\n";
}
else
{
cout << "Add Failure\n";
}
and now my delete function:
string name[100];
string type[100];
int level[100];
int pokemonCount = 0;
string deletedPokemon = "";
bool found = false;
ifstream fin;
cout << "Which Pokemon would you like to delete?" << endl;
getline(cin, deletedPokemon);
cin.ignore(5, '\n');
fin.open("pokemon.txt");
if (fin.is_open())
{
while (isalnum(fin.peek()))
{
getline(fin, name[pokemonCount]);
getline(fin, type[pokemonCount]);
fin >> level[pokemonCount];
fin.clear();
fin.ignore(100, '\n');
if (deletedPokemon == name[pokemonCount])
{
pokemonCount--;
found = true;
}
pokemonCount++;
}
fin.close();
cout << "ya the file opened" << endl; //always appears
}
ofstream fout;
fout.open("pokemon.txt");
if (fout.is_open())
{
for (int i = 0; i < pokemonCount; i++)
{
fout << name[i] << "\n";
fout << type[i] << "\n";
fout << level[i] << endl;
}
fout.close();
cout << "pokemon removed\n";
cout << "the file opened."; //it is returning that the file opened in both occasions in this function but nothing is happening!
}
else
{
cout << "removal failure";
cout << "The file didn't open";
}
return found;
at the end of this function (if I chose to delete one), it will offer the "Would you like to add a Pokemon?" but it wont let me input an answer and it will just end the program.
The default behaviour of ofstream::open is to simply open the file for reading and writing. If you want to overwrite the file, you need to specify it in your call to open.
fout.open("pokemon.txt", ios_base::in|ios_base::out|ios_base::trunc);
Make sure your file is not marked as read-only under properties.
Also, there is a bug in your delete function:
The bfound should be replace with nDelete pokemon and when you write out the file:
if (deletedPokemon == name[pokemonCount])
{
pokemonCount--;
found = true;
nDeleteIndex = i;
}
....
for (int i = 0; i < pokemonCount; i++)
{
if(i == nDeleteIndex)
continue;
fout << name[i] << "\n";
fout << type[i] << "\n";
fout << level[i] << endl;
}
Right now it will re-write all your pokemons without skipping the one you want to delete!
Also, what happens if the user has 155 pokemons for a full index. You want to use:
std::vector<string> names;
....
string szPokemon;
getline(fin, name[numberOfPokemon]);
names.push_back(szPokemon);
Thus you no longer have a limit !
Here is much cleaner code, its much more maintainable and whenever you add/remove a field from the pokemon (Shiny? Male/Female ? Unique ?) you will be able to easily do it inside the CPokemonObject instead of having to copy paste the code 100 times.
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
#define POKEMON_FILE "Pokemon.txt"
class CPokemon
{
public:
string szName;
string szType;
int nLevel;
CPokemon() : szName("Pika"), nLevel(10), szType("Lightning")
{};
void Read(ifstream &file)
{
file >> szName;
file >> szType;
file >> nLevel;
};
void Write(ofstream &file)
{
file << szName << endl;
file << szType << endl;
file << nLevel << endl;
};
void CreatePokemon()
{
//Input Pokemon Info
cout << "Name of Pokemon: ";
getline(cin, szName);
cout << "Pokemon type: ";
getline(cin, szType);
cout << "Pokemon level: "; //weird gap between "Pokemon type" and "pokemon level". I have to press enter twice from "pokemon type" to get to "pokemon level"
cin >> nLevel;
}
};
void WritePokemons(vector<CPokemon>& Pokemons)
{
ofstream fout;
fout.open(POKEMON_FILE);
//check the file open
if (!fout.is_open())
{
cout << "removal failure";
cout << "The file didn't open";
return;
}
//Write out all the pokemons
for (unsigned int i = 0; i < Pokemons.size(); i++)
Pokemons[i].Write(fout);
fout.close();
}
void ReadPokemons(vector<CPokemon>& Pokemons)
{
ifstream fin;
fin.open(POKEMON_FILE);
if (fin.is_open())
{
while (isalnum(fin.peek()))
{
CPokemon Pokemon;
Pokemon.Read(fin);
Pokemons.push_back(Pokemon);
}
fin.close();
cout << "ya the file opened" << endl; //always appears
}
}
bool DeletePokemon()
{
vector<CPokemon> Pokemons;
string szPokemonToDelete = "";
cout << "Which Pokemon would you like to delete?" << endl;
cin >> szPokemonToDelete;
//Read all pokemons
ReadPokemons(Pokemons);
ofstream fout;
fout.open("pokemon.txt");
//check the file open
if (!fout.is_open())
{
cout << "removal failure";
cout << "The file didn't open";
return false;
}
bool bFound = false;
for (unsigned int i = 0; i < Pokemons.size(); i++)
{
//Skip the pokemon to delete
if(Pokemons[i].szName == szPokemonToDelete)
{
bFound = true; //we found the pokemon to delete
continue;
}
Pokemons[i].Write(fout);
}
fout.close();
return bFound;
}
void AddPokemon()
{
vector<CPokemon> Pokemons;
//Read all pokemons from the file
ReadPokemons(Pokemons);
//Create the new porkemon
CPokemon Pokemon;
Pokemon.CreatePokemon();
//Add the pokemon to the list
Pokemons.push_back(Pokemon);
//Output file
WritePokemons(Pokemons);
}

get string array from text list c++

my text file was like
123456123456
Jason
uk
012456788
1000
456789456789
david
uk
012456788
1000
i'm trying to get the data from a text file and save it into arrays
however when i want to store the data from the text file into array it loop non-stop.
what should i do ?
the problem exiting in looping or the method i get the data from text file ?
code:
#include <iostream>
#include <fstream>
using namespace std;
typedef struct {
char acc_no[12];
char name[30];
char address[50];
char phone_no[12];
double balance;
} ACCOUNT;
//function prototype
void menu();
void read_data(ACCOUNT record[]);
int main() {
ACCOUNT record[31]; //Define array 'record' which have maximum size of 30
read_data(record);
}
//--------------------------------------------------------------------
void read_data(ACCOUNT record[]) {
ifstream openfile("list.txt"); //open text file
if (!openfile) {
cout << "Error opening input file\n";
return 0;
} else {
int loop = -1; //size of array
cout << "--------------Data From File--------------"<<endl;
while (!openfile.eof()) {
if (openfile.peek() == '\n')
openfile.ignore(256, '\n');
openfile.getline(record[++loop].acc_no, 12);
openfile.getline(record[loop].name, 30);
openfile.getline(record[loop].address, 50);
openfile.getline(record[loop].phone_no, 12);
openfile >> record[loop].balance;
}
openfile.close(); //close text file
for (int i = 0; i <= loop + 1; i++) {
cout << "Account " << endl;
cout << "Account No. : " << record[i].acc_no << endl;
cout << "Name : " << record[i].name << endl;
cout << "Address : " << record[i].address << endl;
cout << "Phone Number : " << record[i].phone_no << endl;
cout << "Balance : " << record[i].balance << endl;
}
}
}
UPDATE:
The OP didn't properly cite the correct format in his data file. This answer is only valid up until the last iteration.
Don't use .eof() - that's more applicable to when you want to open the file and read it by characters.
A better way would be to use the insertion operator >> as follows:
#define ARR_SIZE 31
ACCOUNT temp;
ACCOUNT record[ARR_SIZE];
int i=0;
while(i < ARR_SIZE) {
openfile >> temp.acc_no >> temp.name >> temp.address >> temp.phone_no >> temp.balance;
record[i] = temp;
i++;
}
Of course, even better is to use std::string to hold the values from the input file, in addition to using std::vectors instead of arrays.

C++. After writing into a relative file, I cannot display the content

I can write into a relative file1, then when I try to read the content and display it on the screen (to check if data are actually into the file), I do not have the records which I believe are already present in the file. I am using Dev-C++. Any help will be appreciated. The code is below;
#include <iostream> // cin, cout
#include <iomanip>
#include <fstream>
#include <conio.h>
using namespace std;
#define SIZE 10
struct client // Client record
{
int account; // from 1 to SIZE
char name[20];
double balance;
};
void make_file(char filename[], int number_of_records)
{
cout << "\nMAKE_FILE: Creating a blank relative file " << filename
<< " containing " << number_of_records << " records.";
ofstream OS(filename, ios::out);
if(!OS) {cerr << "File open error." << endl; exit(1);}
client blank={0, "", 0.0}; // Create an empty client record
while(number_of_records--)
OS.write((char *)&blank, sizeof(blank));
cout << "\nFile created.";
OS.close();
}
int main(void)
{
client c;
void *ptr;
int n=0;
char *fname = "credit.txt";
make_file(fname, SIZE);
fstream iof("credit.txt",ios::in | ios::out);
if(!iof)
{
cerr<<"File open error! "<<endl;
exit(1);
}
cout<<"\n\nenter the 10 customers into the file: "<< fname<<endl<<endl;
while(0 < c.account) // && c.account <= maxrec)
{
iof.seekp((c.account-1) * sizeof(client)); // position the pointer
iof.write((char *)&c, sizeof(c));
cout << "Account[1.."<< SIZE
<< "], Name, Balance (0 0 0 to exit)= ";
cin >> c.account >> c.name >> c.balance;
}
cout << "\n\nSHOW_FILE: The contents of file " << fname;
iof.seekg (0, ios::beg);
while(iof.read((char *)&c, sizeof(c))) //where I think the problem is
{
cout <<'\n'<< setw(3)<< ++n << setw(6) << c.account <<setw(20)
<< c.name << setw(10) << c.balance ;
// << " | " << IS.eof() << " " << ptr;
}
iof.close();
cout << "\n\n";
system("pause");
return 0;
}
A relative file is a file in which each record is identified by its ordinal position in the file allowing for random as well as sequential access.
Relative Files
Relative file organization
http://cayfer.bilkent.edu.tr/~cayfer/ctp108/relative.htm
You need to use binary reading/writing.
fstream iof("credit.txt",ios::in | ios::out | ios::binary);
In your code, in first loop, c.account is not initialitzed. Perhaps you are overwriting file with uninitialized values:
while(0 < c.account) // <--- c.account is not initialized!!
{
iof.seekp((c.account-1) * sizeof(client)); // position the pointer
iof.write((char *)&c, sizeof(c)); // <-- overwriting data??
You're program intrigued me since I haven't done too much work with iostream. If you were ever working with data that had to be edited on a per record basis you'd use some type of database or specialized library that would encapsulate you from all this stuff, such as an xml library. Since your data is so small it's easier to just load all of it into your application using an array of your data structs. After, when you've got new user input, it's easiest clear the file, and the write the data fresh. Here is what I did.
#include <stdio.h>
#include <tchar.h>
#include <iostream> // cin, cout
#include <iomanip>
#include <fstream>
#include <conio.h>
using namespace std;
#define SIZE 10
#define BUFFER_SIZE 100
#define NAME_SIZE 20
struct client // Client record
{
int account; // from 1 to SIZE
char name[NAME_SIZE];
double balance;
};
/* Makes file if files does not exist.
* Returns true if file already exists
*/
bool make_file(char filename[], int number_of_records)
{
// Check if file exists
fstream file;
file.open(filename, ios_base::out | ios_base::in); // will not create file
if (file.is_open())
{
file.close();
return true;
}
else
{
file.clear();
file.open(filename, ios_base::out);
if(!file) {cerr << "File open error." << endl; exit(1);}
cout << "File created. \n";
file.close();
return false;
}
}
/* Create an application that reads x number of accounts from a text file
* into an array of client data structures.
*/
int _tmain(int argc, _TCHAR* argv[])
{
client clientArray[SIZE];
char cleanName[NAME_SIZE];
for(int i = 0; i < NAME_SIZE; i++)
cleanName[i] = NULL;
// Make file if doesn't not exist.
char *fname = "credit.txt";
bool fileExisted = false;
fileExisted = make_file(fname, SIZE);
// initialize client array
for(int j = 0; j < SIZE; j++)
{
clientArray[j].account = -1;
strcpy_s(clientArray[j].name, cleanName);
clientArray[j].balance = 0.0;
}
// Open file and populate the client array
fstream readFile("credit.txt", ios::in | ios::binary);
if(fileExisted)
{
if(!readFile)
{
cerr<<"File open error! "<<endl;
exit(1);
}
int index = 0;
bool firstRun = true;
client temp;
while(index < SIZE)
{
readFile >> temp.account;
readFile >> temp.name;
readFile >> temp.balance;
if(readFile.eof())
break;
if(firstRun)
{
cout << "Data read \n";
cout << "----------\n";
firstRun = false;
}
clientArray[index].account = temp.account;
strcpy_s(clientArray[index].name, temp.name);
clientArray[index].balance = temp.balance;
cout << setw(3) << index+1;
cout << setw(6) << clientArray[index].account;
cout << setw(20) << clientArray[index].name;
cout << setw(10) << clientArray[index].balance << "\n";
index++;
}
readFile.close();
readFile.clear();
}
// Get user input
{
client temp; // Create and initialize temp client
temp.account = 0;
temp.balance = 0;
strcpy_s(temp.name, cleanName);
int index = 0;
bool keepLooping = true;
while(keepLooping)
{
cout << "Account[1.."<< SIZE << "], Name, Balance (-1 to exit)= ";
cin >> temp.account;
// If user exited
if(temp.account == -1)
keepLooping = false;
else
{
cin >> temp.name; // If not keep reading data
cin >> temp.balance;
// Find either unused account or same account
bool found = false;
int firstEmpty = -1;
for(int i = 0; i<SIZE; i++)
{
if(temp.account == clientArray[i].account) // Same account found
{
strcpy_s(clientArray[i].name, temp.name);
clientArray[i].balance = temp.balance;
found = true;
break;
}
else if((clientArray[i].account == -1)&&(firstEmpty == -1)) // Empty account found
{
firstEmpty = i;
}
}
if((firstEmpty != -1)&&(!found)) // Copy input to empty account
{
clientArray[firstEmpty].account = temp.account;
strcpy_s(clientArray[firstEmpty].name, temp.name);
clientArray[firstEmpty].balance = temp.balance;
}
else if(found) //
{
cout << "Updating Client Data. \n";
}
else // No empty accounts break loop
{
cout << "Client array is full!\n";
keepLooping = false;
}
}
}
} // end of user input scope
// Clear file and write only valid data to new file
{
ofstream out;
out.open("credit.txt");
for(int i=0 ; i<SIZE ; i++)
{
if(clientArray[i].account != -1)
{
out << clientArray[i].account << "\t";
out << clientArray[i].name << "\t";
out << clientArray[i].balance << "\n";
}
}
out.close();
out.clear();
}
// Open file and read the data
{
ifstream readFile("credit.txt", ios::in | ios::binary);
// readFile("credit.txt", ios::in | ios::binary);
if(!readFile)
{
cerr<<"File open error! "<<endl;
exit(1);
}
if(!readFile.good())
{
cerr<<"File open error!2"<<endl;
exit(1);
}
int index = 0; // scope variables
client temp;
temp.account = 0;
temp.balance = 0;
strcpy_s(temp.name, cleanName);
cout << "\nAccounts" << "\n";
cout << "----------" << "\n";
bool readFileb = readFile.good();
while(index < SIZE)
{
readFile >> temp.account;
readFile >> temp.name;
readFile >> temp.balance;
if(readFile.eof())
break;
cout << setw(3) << index+1;
cout << setw(6) << temp.account;
cout << setw(20) << temp.name;
cout << setw(10) << temp.balance << "\n";
index++;
}
readFile.close();
readFile.clear();
}
system("pause");
}