Problem loading object data from text file - c++

Why doesn't this code want to load all the values from a text file? It only loads the first object's items correctly but after that it starts going weird. Here is the code:
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
class Location
{
public:
Location()
{
locName = "No Name";
locDesc = "No Description";
locID = 0;
}
friend ostream& operator <<(ostream& outs, const Location & showMe)
{
// keeping output same as input...
outs << showMe.locName << endl;
outs << showMe.locDesc << endl;
outs << showMe.locID << endl;
return outs;
}
friend istream& operator >>(istream& ins, Location & inLoc)
{
getline(ins, inLoc.locName);
getline(ins, inLoc.locDesc);
ins >> inLoc.locID;
return ins;
}
private:
string locName;
string locDesc;
int locID;
};
int main()
{
ifstream inFile;
inFile.open("loc_data.txt");
if (inFile.fail())
{
cout << "\nCould not open the input file!";
exit(1);
}
Location fileLoc[10];
int i = 0;
while (inFile.good())
{
inFile >> fileLoc[i];
i++;
}
for (int j = 0; j < 10; j++)
cout << fileLoc[j];
return 0;
}
The input file is:
Town Hall
Main venue for functions
1
City Park
Outdoor venue
2
Train Station
Commuting point
3
Local Airport
Long distance travel
4
And the output is:
Town Hall
Main venue for functions
1
City Park
0
No Name
No Description
0
No Name
No Description
0
No Name
No Description
0
No Name
No Description
0
No Name
No Description
0
No Name
No Description
0
No Name
No Description
0
No Name
No Description
0
I have a suspucion that getline is responsible for this but do not know enough to be sure, however I would really like to know why this is happening and not just a 'fix'.

Your first problem is that this line doesn't extract the newline character:
ins >> inLoc.locID;
This means that the getline in for the second Location is extracting the rest of the line after 1 - i.e. an empty string - for the name.
This means that you are quickly getting out of sync with the lines that you want to read.
You should also consider changing your while loop, as it stands you check whether the stream is "good" before extracting a new location but you do not check whether the extraction was successful, you assume that the extraction works.

This works:
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <sstream>
using namespace std;
class Location
{
public:
Location()
{
locName = "No Name";
locDesc = "No Description";
locID = 0;
}
friend ostream& operator <<(ostream& outs, const Location & showMe)
{
// keeping output same as input...
outs << showMe.locName << endl;
outs << showMe.locDesc << endl;
outs << showMe.locID << endl;
return outs;
}
friend istream& operator >>(istream& ins, Location & inLoc)
{
getline(ins, inLoc.locName);
getline(ins, inLoc.locDesc);
std::stringstream ss;
std::string s;
getline(ins, s);
ss << s;
ss >> inLoc.locID;
return ins;
}
private:
string locName;
string locDesc;
int locID;
};
int main()
{
ifstream inFile;
inFile.open("loc_data.txt");
if (inFile.fail())
{
cout << "\nCould not open the input file!";
exit(1);
}
Location fileLoc[10];
int i = 0;
while (inFile.good())
{
inFile >> fileLoc[i];
i++;
}
for (int j = 0; j < 10; j++)
cout << fileLoc[j];
return 0;
}

I believe the issue is with this line: ins >> inLoc.locID;
The problem is that when you read this value in with the >> operator it is leaving the next line charactor in the buffer, this then causes the read loop to end (as can be seen if you step through it).
To get around this i think you need to purposely empty this charactor from the buffer or use getline and convert the input (with validation i would hope!) to a number from a string.
Hope this helps,

Related

How to create a filereading program that loads a file of codes

Basically my program is giving me a load of errors with my filereading program when trying to compile. The goal is to get the user to enter the threshold number and the strings that are equal to or greater than that threshold number will be outputted. The program fails at that because there are several errors with the code. How to fix the errors within the code?
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
int read_airports(string cities[], int threshold);
int main()
{
ifstream fin;
fin.open("airports.txt");
if (fin.is_open())
{
string cities[20];
int count, threshold;
count = read_airports(cities, threshold);
while(!fin.eof())
{
fin >> threshold;
cout << "Enter a threshold number" << endl;
cin >> threshold;
if (fin.good())
{
if (cities >= threshold)
{
cout << cities << endl;
}
}
}
fin.close();
}
return 0;
}
int read_airports(string cities[], int threshold)
{
}
Here is the text file where this code is based off of.
LAX Los-Angeles 40
JFK New-York 39
IAH Houston 26
LCY London 34
PAR Paris 15
TYO Tokyo 11
SEL Seoul 5
YYZ Toronto 28
[Warning: none of this code has been tested at all.]
I would structure the code rather differently.
I would create a structure for the data about each airport/city:
struct airport {
std::string abbreviation;
std::string city_name;
int threshold;
};
Then I'd overload operator>> to read one of those records from a stream, and operator<< to write one to a stream:
std::istream &operator>>(std::istream &is, airport &ap) {
return is >> ap.abbreviation >> ap.city_name >> ap.threshold;
}
std::ostream &operator<<(std::ostream &os, airport const &ap) {
return os << ap.abbreviation << "\t" << ap.city_name << "\t" << ap.threshold;
}
Then I'd write code to desired data from a file of those to standard output:
std::ifstream infile("airportdata.txt");
std::cout << "Please enter minimum threshold value: ";
int threshold;
std::cin >> threshold;
std::copy_if(std::istream_iterator<airport>(infile), {},
std::ostream_iterator<airport>(std::cout, "\n"),
[=](airport const &ap) { return ap.threshold > threshold; });

Using int alongside string and getline without errors

I'm creating a program that reads the author, title, and number of volumes from a file and prints out labels,
(ex.
Adams
A Complete History of the World
Volume 1 of 10
Adams
A Complete History of the World
Volume 2 of 10 etc.)
To make it read properly and not infinitely loop, I had to change all of my variable to string. However, for future reference to the volume number, I need it to be int so I can compare the amount.
My ideas for furthering the code with a do-while loop are commented in to show why I'd like vnum to have int value.
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main()
{
ifstream fin;
string author;
string title;
string vnum;
int counter=1;
fin.open("publish.txt", ios::in);
while (!fin.eof())
{
getline(fin, author);
getline(fin, title);
getline(fin, vnum);
//do
//{
cout << author << endl;
cout << title << endl;
cout << "Volume " << counter << " of " << vnum << endl;
cout << endl;
//counter++;
//} while(counter < vnum);
}
fin.close();
return 0;
}
File I'm reading from:
Adams
A Complete History of the World
10
Samuels
My Life of Crime
2
Baum
Wizard Stories
6
First of all, avoid use of
while (!fin.eof())
See Why is “while ( !feof (file) )” always wrong? to understand the problems it would cause.
Coming to your task, I would suggest:
Create a struct to hold the data.
Add a function to read all the members of the struct from a std::istream.
Add a function to write all the members of the struct to a std::ostream.
Simplify main to use the above.
Here's what I suggest:
struct Book
{
std::string author;
std::string title;
int volume;
};
std::istream& operator>>(std::istream& in, Book& book);
std::ostream& operator<<(std::ostream& out, Book const& book);
That will help simplify main to:
int main()
{
ifstream fin;
Book book;
// Not sure why you would need this anymore.
int counter=1;
fin.open("publish.txt", ios::in);
while ( fin >> book )
{
cout << book;
++counter;
}
return 0;
}
The functions to read and write a Book can be:
std::istream& operator>>(std::istream& in, Book& book)
{
// Read the author
getline(in, book.author);
// Read the title
getline(in. book.title);
// Read the volume
in >> book.volume;
// Ignore rest of the line.
in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
return in;
}
std::ostream& operator<<(std::ostream& out, Book const& book)
{
out << book.author << std::endl;
out << book.title << std::endl;
out << book.volume << std::endl;
return out;
}

How to read from a file and store the data to a structure and calculate formula?

I'm new to C++. I have a file named test.txt with following data
2
Salman Khan
20 100000 4.75 1000
Aamir khan
30 200000 5.25 1000
where
the first line is the number of user records,
the second line is Name separated by space, and
the third line consists of years, amount, rate, amount per month that the user is qualified.
I want to calculate formula and show into a table.
so far i've done is as follow:
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;
struct Customers
{
char first_name[50];
char last_name[30];
int years;
float amount;
float interest_rate;
float amount_per_month;
};
int main() {
Customers cus;
int sum = 0;
string x,line;
string fileName = "";
ifstream inFile;
string firstLine;
int numberOfCustomers = 0;
cout << "Enter File Name: \n";
cin >> fileName;
cout << "Reading File : '"+ fileName+"'" << endl;
inFile.open(fileName);
if (!inFile) {
cout << "Unable to open file";
exit(1); // terminate with error
}
if (inFile.good())
{
getline(inFile, firstLine);
numberOfCustomers = stoi(firstLine);
cout << "Available Loan Applications : " << numberOfCustomers << endl;
}
while (inFile >> x) {
cout << x << endl;
cin >> cus.first_name;
}
inFile.close();
return 0;
}
I'm trying to store data to structure and then calculate, i need help in storing data to structure.
You can use stream extraction and stream insertion operators to read/write custom datatypes:
#include <cstddef> // std::size_t
#include <cstdlib> // EXIT_FAILURE
#include <iterator> // std::istream_iterator<>
#include <vector> // std::vector<>
#include <string> // std::string
#include <fstream> // std::ifstream
#include <iostream> // std::cout, std::cerr, std::ostream, std::istream
using namespace std;
struct Customer {
string first_name, last_name;
int years;
float amount, interest_rate, amount_per_month;
};
// define a stream extraction operator that takes a Customer on the right hand side
// usage examples: std::cin >> customer;
// file >> customer;
istream& operator>>(istream &is, Customer &customer)
{
// don't write directly into the members of Customer to not leave
// the object in a flunky state if extraction fails for some value.
string first_name, last_name;
int years;
float amount, interest_rate, amount_per_month;
if (!(is >> first_name >> last_name >> years >> amount >> interest_rate >> amount_per_month))
return is; // if extraction of a value fails end here
// if we reach here all values have been read successfully and can be
// assigned to the customer:
customer = { first_name, last_name, years, amount, interest_rate, amount_per_month };
return is;
}
// define a stream insertion operator that takes a Customer on the right hand side
// usage examples: std::cout << customer;
// file << customer;
ostream& operator<<(ostream &os, Customer const &customer)
{
os << customer.first_name << ' ' << customer.last_name << '\n' << customer.years << ' '
<< customer.amount << ' ' << customer.interest_rate << ' ' << customer.amount_per_month;
return os;
}
int main()
{
cout << "Enter filename: ";
string fileName;
cin >> fileName;
ifstream inFile{ fileName }; // define variables as close to where they're
// used. Use the constructor where app-
// ropriate - here to open the file.
if (!inFile.is_open()) { // if the file couldn't be opened
cerr << "Unable to open \"" << fileName << "\" for reading!\n\n";
return EXIT_FAILURE; // exit main() returning a value that
} // indicates an error
cout << "Reading file \"" + fileName + "\":\n";
size_t numCustomers;
if (!(inFile >> numCustomers)) { // read the number of customers before-
// hand since this value is not part of
// a customer record.
cerr << "Couldn't read number of customers from \"" << fileName << "\"!\n\n";
return EXIT_FAILURE;
}
// use an istream_iterator that will use our stream extraction operator
// to read customers from inFile until it reaches EOF or an error occurs.
vector<Customer> Customers{ istream_iterator<Customer>{ inFile },
istream_iterator<Customer>{} };
if (numCustomers != Customers.size()) { // check if the number of customers
// specified in the file matches
// the number of customers we
// were able to extract.
cerr << "Number of customers specified in \"" << fileName
<< "\" does not match the number of customers read!\n\n";
return EXIT_FAILURE; // if the numbers don't match there was an error
} // while reading the records from the file
for (auto const &c : Customers) // just to check print the customers
std::cout << c << '\n';
}
Output:
Enter File Name: test.txt
Reading file "test.txt":
Salman Khan
20 100000 4.75 1000
Aamir khan
30 200000 5.25 1000

C++ Validate Emails Via Substrings

I'm trying to take the profile info(username, email, etc.) from one directory and put it in another. I've been debugging the code for this program, and while there are no errors, the program won't run, saying that the program "has stopped working". I have already looked on this website and others for any possible answers, and found none.
#include <string>
#include <cstring>
#include <iostream>
#include <istream>
#include <ostream>
#include <fstream>
#include <iomanip>
#include <filesystem>
using namespace std;
class path{
public:
string parent_directory;
string root_directory;
};
class Data{
public:
string userName;
string nickName;
string fName;
string arena_FName;
string lName;
string arena_LName;
string email;
string arenaEmail;
friend std::istream& operator>>(std::istream& input, Data& d);
};
std::istream& operator>>(std::istream& input, Data& d){
std::getline(input, d.userName);
std::getline(input, d.nickName);
//...
std::getline(input, d.arenaEmail);
return input;
}
int main(){
ifstream myfile("myfunk.txt", ios::in);
ofstream arena("arena.txt");
myfile.open("myfunk.txt", ios::in);
if(myfile){
cout << "Input file open." << endl;
}
arena.open("arena.txt", ios::out | ios::app);
if(arena){
cout << "Output file open." << endl;
}
cout << "file opening test: success" << endl;
int x = 0;
int y = 4101; //Total number of users in the directory.
int z = 0; //For inputting the required lines of info for each profile.
int profile = 0;
bool valid = false;
string role;
//string arenaRole;
bool post = false;
string line;
string p = "This PC/..."; //Path to the folder of the individual pictures.
//myVar.save("...");
string p = "...";
path path1;
path root_directory;
path parent_directory;
//bool is_directory(const std::filesystem::path& p, std::error_code& ec) noexcept; //Checks if current location is a directory.
//bool postPic;
const unsigned int MAXIMUM_DATA = 4100u;
Data database[MAXIMUM_DATA];
cout << "All variables but the filesystem have been accepted! Please install this program on the network." << endl;
while(x < y){
cout << "Primary loop functioning" << endl;
if(post = true){
getline(myfile, line); //Grab and read next line.
myfile >> line;
line = userName[x];
arena << "Username: " << userName[x] << "\n";
z++;
getline(myfile, line);
myfile >> line;
line = role[x];
arena << "Role: " << role[x] << "\n";
z++;
getline(myfile, line);
line = nickName[x];
myfile >> nickName[x];
arena << "nickname: " << nickName[x] << "\n";
z++;
getline(myfile, line);
line = fName[x];
myfile >> fName;
arena << "First Name: " << fName[x] << "\n";
z++;
getline(myfile, line);
line = lName[x];
myfile >> lName;
arena << "Last Name: " << lName[x] << "\n";
z++;
getline(myfile, line);
myfile >> line;
line = email[x];
arena << "Email: " << email[x] << "\n";
getline(myfile, line);
z = 0; //Next profile...
}
int data;
while(myfile >> data){
if(nickName[x] = NULL){
myfile >> "<Error> Some required information is missing! Contact user! </Error> /n";
valid = false;
post = false;
x++;
}
if(email[x] != NULL){
std::string str("#");
std::string str2(".com");
std::string str3(".net");
std::string str4(".edu");
if(std::size_t found = email[x].find(str) & (std::size_t found = email[x].find(str2) || std::size_t found = email[x].find(str3) || std::size_t found = email[x].find(str4)){
valid = true;
if(valid = true){
post = true;
}
}
else{
valid = false;
post = false;
x++;
}
}
}
}
}
}
x++;
}
//x++;
myfile.close(); //Closes the file in the directory.
arena.close(); //Closes the file in Arena.
return 0;
}
Let's rework your code.
First, let's create a data structure for the data:
class Data
{
public:
string userName;
string nickName;
string fName;
string arena_FName;
string lName;
string arena_LName;
string email;
string arenaEmail;
};
If you need an array for the data, it would be declared as:
const unsigned int MAXIMUM_DATA = 4100u;
Data database[MAXIMUM_DATA];
Next, let's overload the extraction operator>> to make reading easier:
class Data
{
public:
//...
friend std::istream& operator>>(std::istream& input, Data& d);
};
std::istream& operator>>(std::istream& input, Data& d)
{
std::getline(input, d.userName);
std::getline(input, d.nickName);
//...
std::getline(input, d.arenaEmail);
return input;
}
This simplifies your input loop to:
std::vector<Data> database;
Data d;
while (my_file >> d)
{
database.push_back(d);
}
You can query the amount of data read in by using the std::vector::size() method, i.e. database.size().
Also, you don't need a separate structure for a file path. A simple std::string will suffice. I recommend using forward slash, '/', because it is recognized by both Windows and *nix operating systems and won't be interpreted as an escape character.

File to Array to Struct

I'm working on this program that is to help manage a DVD rental store. What I have to do is take a text that contains info about DVD etc:
Mean girls; comedy; PG; 2009; Regina George; 12.07.2015;
The Conjuring; Horror; R; 2013; Sara Johnson; 16.05.2016;
Pokemon 2000; Kids; G; 2000; Ash Katchem; 15.04.2016;
etc..
And then takes this information and then reads it into an array and from there the array is read into the struct and then displayed in proper order like so:
Name: Mean Girls
Genre: Comedy
Rating: PG
etc...
This is my code so far:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
struct dvd{
string name;
string genre;
string rating;
string released;
string renter;
string rentday;
void print();
bool read(ifstream & file);
};
void dvd::print(){
cout <<"Title: " << name << endl;
cout <<"Genre: " << genre << endl;
cout << "Rating: " << rating << endl;
cout << "Release date: " << released << endl;
cout << "Name of renter: " << renter << endl;
cout << "Date rented: " << rentday << endl;
}
bool dvd::read(ifstream & file)
{
getline(file, name, ';');
getline(file, genre, ';');
getline(file, rating,';');
getline(file, released, ';');
getline(file, renter, ';');
getline(file, rentday, ';');
return file.good();
}
int main() {
vector<dvd> dvds;
dvd dvd1;
ifstream file("DVD.txt");
if(! file.is_open()){
cout << "Failed to find input file" << endl;
return 1;
}
while(dvd1.read(file))
{ dvds.push_back(dvd1);
}
dvd1.print();
return 0;
}
So what I would like to do is have read the text file into the Array and from there read the Array into the struct. So instead of the text file reading into the vector I need it to read into the array and from there read the first line of the array (dvdArray[1]) into struct dvd and then print out that information using print function and then loop that until dvdArray[10] is read into struct dvd!
Thank you so much for your help! :)
Change
bool dvd::read(ifstream & file)
to
bool dvd::read(istream & file)
No other changes to its contents are required.
Then, take each line and put it into a std::istringstream, then pass it to dvd::read.
You should be able to figure out the rest on your own.
For simple reading from and writing to file, I would suggest overload << and >> for your struct class, in order to make the code easy to serialize and de-serialize in a readable fashion.
friend std::ostream& operator<< (std::ostream& stream, const dvd& dvdObj)
{
// your output stuff
// stream <<"Title: " << dvdObj.name << endl;
// ...
return stream;
}
friend std::istream& operator>> (std::istream& stream, dvd& dvdObj)
{
// your output stuff
// getline(stream, dvdObj.name, ';');
// ...
return stream;
}
Then,
// look for std::copy for reading directly into vector ... else
while( file >> dvd1 )
{
dvds.push_back(dvd1);
}
And,
for( const auto& dvd1: dvds )
{
std::cout << dvd1 ;
}