when reading a file using c++, How to ignore a line - c++

I want to read custom file structure and output them, also i want to ignore the lines which are not in the right format. Like comments, titles, etc.,
I've tried this code but its stop looping when it meets a line which is out of the structure.
Here is the txt file.
1001 Promod Dinal IT-K20 42 42
1002 Sahan Navod BM-K11 65 28
day_02
1003 Kaushani Dilinika BM-K12 69 49
1004 Fathima Sahana QS-K14 73 43
int main()
{
ifstream thefile;
thefile.open("GameZone.txt");
int id;
char fName[30];
char lName[30];
char stream[30];
int score;
int time;
if (!thefile.is_open()) {
cout << "cant open the file" << endl;
}
else {
while (!thefile.eof()) {
if (thefile >> id >> fName >> lName >> stream >> score >> time) {
cout << id << " ," << fName << " ," << lName << " ," << stream << " ," << score << " ," << time << endl;
}else if(!(thefile >> id >> fName >> lName >> stream >> score >> time)){
cout << "skip the row" << endl;
continue;
}
}
}
return 0;
}
Output
1001 ,Promod ,Dinal ,IT-K20 ,42 ,42
1002 ,Sahan ,Navod ,BM-K11 ,65 ,28

Do not try to parse fields directly from the file. Instead, read lines from the file and attempt to parse those lines. Use the following algorithm:
Read a line from the file.
If you were not able to read a line, stop, you are done.
Try to parse the line into fields.
If you were not able to parse the line, go to step 1.
Process the fields.
Go to step 1.

If you are still having difficulty with the implementation, then a very simple implementation would simple read each line, create a stringstream from the line to allow you to attempt to parse your values from, then depending on the result of reading from the stringstream output your values in your (rather strange " ,") csv format, or simply go read the next line and try again.
You should be using std::string instead of char[] to holds your string data in C++. Either will work, but the latter is much more user-friendly and flexible. In either case, you will want to coordinate all the differing types of data that make up one record as a struct. This has many benefits if you are actually doing something more than just dumping your data to stdout. For example, you can store all of your data read in a std::vector of struct and then be able to further process your data (e.g. sort, push_back, or erase records) as needed or pass it to other functions for further processing.
A simple struct using int and std::string could be:
struct record_t { /* simple struct to coordinate data in single record */
int id, score, time;
std::string fname, lname, stream;
};
The reading and outputting of records in your csv format, can then be as simple as using a temporary struct to attempt to parse the line into, and if successful, output (or further use) the data as needed, e.g.
std::string line; /* string to hold line */
std:: ifstream fin (argv[1]); /* in stream for file */
while (getline (fin, line)) { /* read entire line into line */
std::stringstream ss (line); /* create stringstream from line */
record_t record; /* temp struct to read into */
if (ss >> record.id >> record.fname >> record.lname >>
record.stream >> record.score >> record.time)
/* if successful read from stringstream, output record */
std::cout << record.id << " ," << record.fname << " ,"
<< record.lname << " ," << record.stream << " ,"
<< record.score << " ," << record.time << '\n';
}
Putting it altogether in a short example that takes the file to be read as the first argument to the program could be:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
struct record_t { /* simple struct to coordinate data in single record */
int id, score, time;
std::string fname, lname, stream;
};
int main (int argc, char **argv) {
if (argc < 2) { /* validate at least 1 argument provided */
std::cerr << "error: filename required.\n";
return 1;
}
std::string line; /* string to hold line */
std:: ifstream fin (argv[1]); /* in stream for file */
while (getline (fin, line)) { /* read entire line into line */
std::stringstream ss (line); /* create stringstream from line */
record_t record; /* temp struct to read into */
if (ss >> record.id >> record.fname >> record.lname >>
record.stream >> record.score >> record.time)
/* if successful read from stringstream, output record */
std::cout << record.id << " ," << record.fname << " ,"
<< record.lname << " ," << record.stream << " ,"
<< record.score << " ," << record.time << '\n';
}
}
(note: do not hard-code filenames or use magic numbers in your code)
Example Use/Output
Output in your rather odd " ," csv format:
$ ./bin/readrecords dat/records.txt
1001 ,Promod ,Dinal ,IT-K20 ,42 ,42
1002 ,Sahan ,Navod ,BM-K11 ,65 ,28
1003 ,Kaushani ,Dilinika ,BM-K12 ,69 ,49
1004 ,Fathima ,Sahana ,QS-K14 ,73 ,43
To make things slightly more useful, you can, instead of simply outputting the records directly, store all records in a std::vector<record_t> (vector of struct). This then opens the possibility of further processing your data. See if you can understand the changes made below on how each record is stored in a vector and then a Range-based for loop is used to loop over each record held in the vector to output your information.
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
struct record_t { /* simple struct to coordinate data in single record */
int id, score, time;
std::string fname, lname, stream;
};
int main (int argc, char **argv) {
if (argc < 2) { /* validate at least 1 argument provided */
std::cerr << "error: filename required.\n";
return 1;
}
std::string line; /* string to hold line */
std:: ifstream fin (argv[1]); /* in stream for file */
std::vector<record_t> records; /* vector of records */
while (getline (fin, line)) { /* read entire line into line */
std::stringstream ss (line); /* create stringstream from line */
record_t record; /* temp struct to read into */
if (ss >> record.id >> record.fname >> record.lname >>
record.stream >> record.score >> record.time)
records.push_back(record); /* if good read, add to vector */
}
if (records.size() > 0) /* validate vector contains records */
for (auto& r : records) /* loop over all records */
std::cout << r.id << " ," << r.fname << " ," << r.lname << " ,"
<< r.stream << " ," << r.score << " ," << r.time << '\n';
else /* if no records read, throw error */
std::cerr << "error: no records read from file.\n";
}
Look things over and let me know if you have any further questions.

Related

how to display text file in c++?

I want to display the text file in my c++ program but nothing appears and the program just ended. I am using struct here. I previously used this kind of method, but now I am not sure why it isn't working. I hope someone could help me. Thanks a lot.
struct Records{
int ID;
string desc;
string supplier;
double price;
int quantity;
int rop;
string category;
string uom;
}record[50];
void inventory() {
int ID, quantity, rop;
string desc, supplier, category, uom;
double price;
ifstream file("sample inventory.txt");
if (file.fail()) {
cout << "Error opening records file." <<endl;
exit(1);
}
int i = 0;
while(! file.eof()){
file >> ID >> desc >> supplier >> price >> quantity >> rop >> category >> uom;
record[i].ID = ID;
record[i].desc = desc;
record[i].supplier = supplier;
record[i].price = price;
record[i].quantity = quantity;
record[i].rop = rop;
record[i].category = category;
record[i].uom = uom;
i++;
}
for (int a = 0; a < 15; a++) {
cout << "\n\t";
cout.width(10); cout << left << record[a].ID;
cout.width(10); cout << left << record[a].desc;
cout.width(10); cout << left << record[a].supplier;
cout.width(10); cout << left << record[a].price;
cout.width(10); cout << left << record[a].quantity;
cout.width(10); cout << left << record[a].rop;
cout.width(10); cout << left << record[a].category;
cout.width(10); cout << left << record[a].uom << endl;
}
file.close();
}
Here is the txt file:
Here are a couple of things you should consider.
Declare the variables as you need them. Don’t declare them at the top of your function. It makes the code more readable.
Use the file’s full path to avoid confusions. For instance "c:/temp/sample inventory.txt".
if ( ! file ) is shorter.
To read data in a loop, use the actual read as a condition while( file >> ID >>... ). This would have revealed the cause of your problem.
Read about the setw manipulator.
file's destructor will close the stream - you don't need to call close()
Your file format consists of a header and data. You do not read the header. You are trying to directly read the data. You try to match the header against various data types: strings, integers, floats; but the header is entirely made of words. Your attempt will invalidate the stream and all subsequent reading attempts will fail. So, first discard the header – you may use getline.
Some columns contain data consisting of more than one word. file >> supplier reads one word, not two or more. So you will get "Mongol", not "Mongol Inc." Your data format needs a separator between columns. Otherwise you won’t be able to tell where the column ends. If you add a separator, again, you may use getline to read fields.
The CATEGORY column is empty. Trying to read it will result in reading from a different column. Adding a separator will also solve the empty category column problem.
This is how your first rows will look like if you use comma as separator:
ID,PROD DESC,SUPPLIER,PRICE,QTY,ROP,CATEGORY,UOM
001,Pencil,Mongol Inc.,8,200,5,,pcs
A different format solution would be to define a string as a zero or more characters enclosed in quotes:
001 "Pencil" "Mongol Inc." 8 200 5 "" "pcs"
and take advantage of the quoted manipulator (note the empty category string):
const int max_records_count = 50;
Record records[max_records_count];
istream& read_record(istream& is, Record& r) // returns the read record in r
{
return is >> r.ID >> quoted(r.desc) >> quoted(r.supplier) >> r.price >> r.quantity >> r.rop >> quoted(r.category) >> quoted(r.uom);
}
istream& read_inventory(istream& is, int& i) // returns the number of read records in i
{
//...
for (i = 0; i < max_records_count && read_record(is, records[i]); ++i)
; // no operation
return is;
}
Unfortunately you text file is not a typical CSV file, delimited by some character like a comma or such. The entries in the lines seem to be separated by tabs. But this is a guess by me. Anyway. The structure of the source file makes it harder to read.
Additionally, the file has an header and while reading the first line andtry to read the word "ID" into an int variable, this conversion will fail. The failbit of the stream is set, and from then on all further access to any iostream function for this stream will do nothing any longer. It will ignore all your further requests to read something.
Additional difficulty is that you have spaces in data fields. But the extractor operator for formatted input >> will stop, if it sees a white space. So, maybe only read half of the field in a record.
Solution: You must first read the header file, then the data rows.
Next, you must know if the file is really tab separated. Sometimes tabs are converted to spaces. In that case, we would need to recreate the start position of a field in the a record.
In any case, you need to read a complete line, and after that split it in parts.
For the first solution approach, I assume tab separated fields.
One of many possible examples:
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
#include <iomanip>
const std::string fileName{"r:\\sample inventory.txt"};
struct Record {
int ID;
std::string desc;
std::string supplier;
double price;
int quantity;
int rop;
std::string category;
std::string uom;
};
using Database = std::vector<Record>;
int main() {
// Open the source text file with inventory data and check, if it could be opened
if (std::ifstream ifs{ fileName }; ifs) {
// Here we will store all data
Database database{};
// Read the first header line and throw it away
std::string line{};
std::string header{};
if (std::getline(ifs, header)) {
// Now read all lines containing record data
while (std::getline(ifs, line)) {
// Now, we read a line and can split it into substrings. Assuming the tab as delimiter
// To be able to extract data from the textfile, we will put the line into a std::istrringstream
std::istringstream iss{ line };
// One Record
Record record{};
std::string field{};
// Read fields and put in record
if (std::getline(iss, field, '\t')) record.ID = std::stoi(field);
if (std::getline(iss, field, '\t')) record.desc = field;
if (std::getline(iss, field, '\t')) record.supplier = field;
if (std::getline(iss, field, '\t')) record.price = std::stod(field);
if (std::getline(iss, field, '\t')) record.quantity = std::stoi(field);
if (std::getline(iss, field, '\t')) record.rop = std::stoi(field);
if (std::getline(iss, field, '\t')) record.category = field;
if (std::getline(iss, field)) record.uom = field;
database.push_back(record);
}
// Now we read the complete database
// Show some debug output.
std::cout << "\n\nDatabase:\n\n\n";
// Show all records
for (const Record& r : database)
std::cout << std::left << std::setw(7) << r.ID << std::setw(20) << r.desc
<< std::setw(20) << r.supplier << std::setw(8) << r.price << std::setw(7)
<< r.quantity << std::setw(8) << r.rop << std::setw(20) << r.category << std::setw(8) << r.uom << '\n';
}
}
else std::cerr << "\nError: COuld not open source file '" << fileName << "'\n\n";
}
But to be honest, there are many assumptions. And tab handling is notoriously error prone.
So, let us make the next approach and extract the data according to their position in the header string. So, we will check, where each header string starts and use this information to later split a complete line into substrings.
We will use a list of Field Descriptors and search for their start position and width in the header line.
Example:
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
#include <iomanip>
#include <array>
const std::string fileName{"r:\\sample inventory.txt"};
struct Record {
int ID;
std::string desc;
std::string supplier;
double price;
int quantity;
int rop;
std::string category;
std::string uom;
};
constexpr size_t NumberOfFieldsInRecord = 8u;
using Database = std::vector<Record>;
int main() {
// Open the source text file with inventory data and check, if it could be opened
if (std::ifstream ifs{ fileName }; ifs) {
// Here we will store all data
Database database{};
// Read the first header line and throw it away
std::string line{};
std::string header{};
if (std::getline(ifs, header)) {
// Analyse the header
// We have 8 elements in one record. We will store the positions of header items
std::array<size_t, NumberOfFieldsInRecord> startPosition{};
std::array<size_t, NumberOfFieldsInRecord> fieldWidth{};
const std::array<std::string, NumberOfFieldsInRecord> expectedHeaderNames{ "ID","PROD DESC","SUPPLIER","PRICE","QTY","ROP","CATEGORY","UOM"};
for (size_t k{}; k < NumberOfFieldsInRecord; ++k)
startPosition[k] = header.find(expectedHeaderNames[k]);
for (size_t k{ 1 }; k < NumberOfFieldsInRecord; ++k)
fieldWidth[k - 1] = startPosition[k] - startPosition[k - 1];
fieldWidth[NumberOfFieldsInRecord - 1] = header.length() - startPosition[NumberOfFieldsInRecord - 1];
// Now read all lines containing record data
while (std::getline(ifs, line)) {
// Now, we read a line and can split it into substrings. Based on poisition and field width
// To be able to extract data from the textfile, we will put the line into a std::istrringstream
std::istringstream iss{ line };
// One Record
Record record{};
std::string field{};
// Read fields and put in record
field = line.substr(startPosition[0], fieldWidth[0]); record.ID = std::stoi(field);
field = line.substr(startPosition[1], fieldWidth[1]); record.desc = field;
field = line.substr(startPosition[2], fieldWidth[2]); record.supplier = field;
field = line.substr(startPosition[3], fieldWidth[3]); record.price = std::stod(field);
field = line.substr(startPosition[4], fieldWidth[4]); record.quantity = std::stoi(field);
field = line.substr(startPosition[5], fieldWidth[5]); record.rop = std::stoi(field);
field = line.substr(startPosition[6], fieldWidth[6]); record.category = field;
field = line.substr(startPosition[7], fieldWidth[7]); record.uom = field;
database.push_back(record);
}
// Now we read the complete database
// Show some debug output.
std::cout << "\n\nDatabase:\n\n\n";
// Header
for (size_t k{}; k < NumberOfFieldsInRecord; ++k)
std::cout << std::left << std::setw(fieldWidth[k]) << expectedHeaderNames[k];
std::cout << '\n';
// Show all records
for (const Record& r : database)
std::cout << std::left << std::setw(fieldWidth[0]) << r.ID << std::setw(fieldWidth[1]) << r.desc
<< std::setw(fieldWidth[2]) << r.supplier << std::setw(fieldWidth[3]) << r.price << std::setw(fieldWidth[4])
<< r.quantity << std::setw(fieldWidth[5]) << r.rop << std::setw(fieldWidth[6]) << r.category << std::setw(fieldWidth[7]) << r.uom << '\n';
}
}
else std::cerr << "\nError: COuld not open source file '" << fileName << "'\n\n";
}
But this is still not all.
We should wrap all functions belonging to a record into the struct Record. And the same for the data base. And espcially we want to overwrite the extractor and the inserter operator. Then input and output will later be very simple.
We will save this for later . . .
If you can give more and better information regarding the structure of the source file, then I will update my answer.

Reading only the formatted data in a file that has formatted and unformatted data using c++

I have a data file with an unknown amount of unformatted, not needed data at the start and end of the file. But, in the middle, the data is precisely formatted and the first column will always start with one of a couple keywords. I want to skip to this part and read in that data, assigning each column to a variable. This would be simple if there wasn't the start and end "garbage" text.
Here is simple example problem. In my real code, each variable is part of a structure. I do not think this will matter, but mention it just in case...
here is my text file, I want all lines that start with keyword, and I want all columns assigned to variables
REMARK: this should be simpler
REMARK: yes, it should
REMARK: it is simple, you just don't see it yet
Comment that doesn't start with REMARK
keyword aaa 1 bbb 1 1.2555 O
keyword aaa 1 bbb 2 2.2555 H
keyword aaa 1 bbb 3 3.2555 C
keyword aaa 1 bbb 4 4.2555 C
END
Arbitrary garbage texts
if there were no random comments, I could use
int main{
string filename = "textfile.pdb";
string name1,name2,name3;
int int1, int2;
double number;
ifstream inFile;
inFile.open(filename.c_str());
while (inFile.good())
{
inFile >> keyword >> name1 >>
int1>>name2>>int2>>number>>name3;
}
inFile.close();
}
I tried getting around this by using
while (getline(inFile,line))
This method lets me look at the line, and check if it has "keyword" in it. but then I couldn't use the convenient formatted input of the first method. I need to parse the string, which seems tricky in c++.I tried using sscanf but it complained about str to char.
The first method is nicer, I just don't know how to implement a check to only read in the line to the variables, if the line is a formatted one.
I'd suggest something like this:
Parsing text file in C++
string name,age,salary,hoursWorked,randomText;
ifstream readFile("textfile.txt");
while(getline(readFile,line)) {
stringstream iss(line);
getline(iss, name, ':');
getline(iss, age, '-');
getline(iss, salary, ',');
getline(iss, hoursWorked, '[');
getline(iss, randomText, ']');
}
readFile.close();
You can easily locate only the formatted lines you are interested in by reading each line and creating a stringstream from the line and validating the line begins with "keyword" and that it contains each remaining item. Since you are using stringstream, you need not read all values as a string, you can simply read the value as the desired type. If the line begins with END, you are done reading, just break;, otherwise if the first word is not "keyword", just read the next line from the file and try again.
After opening an ifstream to your data file as f, you could do the following to locate and parse the wanted data:
while (getline (f, line)) { /* read each line */
int aval, bval; /* local vars for parsing line */
double dblval;
std::string kw, a, b, ccode;
std::stringstream s (line); /* stringstream to parse line */
/* if 1st word not keyword, handle line appropriately */
if ((s >> kw) && kw != "keyword") {
if (kw == "END") /* done with data */
break;
continue; /* otherwise get next line */
} /* read/validate all other data values */
else if ((s >> a) && (s >> aval) && (s >> b) && (s >> bval) &&
(s >> dblval) && (s >> ccode))
std::cout << kw << " " << a << " " << aval << " " << b <<
" " << bval << " " << dblval << " " << ccode << '\n';
else { /* otherwise invalid data line */
std::cerr << "error: invalid data: " << line;
continue;
}
}
(which just outputs the wanted values to stdout, you can use them as needed)
Putting it altogether in a short example to use with your data, you could do something similar to:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
int main (int argc, char **argv) {
std::string line; /* string to hold each line */
if (argc < 2) { /* validate at least 1 argument given */
std::cerr << "error: insufficient input.\n"
"usage: " << argv[0] << " filename\n";
return 1;
}
std::ifstream f (argv[1]); /* open file */
if (!f.is_open()) { /* validate file open for reading */
perror (("error while opening file " +
std::string(argv[1])).c_str());
return 1;
}
while (getline (f, line)) { /* read each line */
int aval, bval; /* local vars for parsing line */
double dblval;
std::string kw, a, b, ccode;
std::stringstream s (line); /* stringstream to parse line */
/* if 1st word not keyword, handle line appropriately */
if ((s >> kw) && kw != "keyword") {
if (kw == "END") /* done with data */
break;
continue; /* otherwise get next line */
} /* read/validate all other data values */
else if ((s >> a) && (s >> aval) && (s >> b) && (s >> bval) &&
(s >> dblval) && (s >> ccode))
std::cout << kw << " " << a << " " << aval << " " << b <<
" " << bval << " " << dblval << " " << ccode << '\n';
else { /* otherwise invalid data line */
std::cerr << "error: invalid data: " << line;
continue;
}
}
f.close();
}
Example Input File
$ cat dat/formatted_only.txt
REMARK: this should be simpler
REMARK: yes, it should
REMARK: it is simple, you just don't see it yet
Comment that doesn't start with REMARK
keyword aaa 1 bbb 1 1.2555 O
keyword aaa 1 bbb 2 2.2555 H
keyword aaa 1 bbb 3 3.2555 C
keyword aaa 1 bbb 4 4.2555 C
END
Arbitrary garbage texts
Example Use/Output
$ ./bin/sstream_formatted_only dat/formatted_only.txt
keyword aaa 1 bbb 1 1.2555 O
keyword aaa 1 bbb 2 2.2555 H
keyword aaa 1 bbb 3 3.2555 C
keyword aaa 1 bbb 4 4.2555 C
Look things over and let me know if you have further questions.

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

Am i using ifstream::fail() method in bad way?

I have the txt file which contains for example:
Arthur 20
Mark 21
Josh 12
The are no empty lanes between, its only for readability!
What I want to do is write it on the screen in the same way as it is in the file.
I tried to make it this way:
ifstream file;
string word;
file.open("data.txt");
while(!file.eof()){
file >> word;
if(file.fail())
break;
cout << word << " ";
file >> word;
cout << word << endl;
}
But the output is:
Arthur 20
Mark 21
Josh 12
0
So why this 0 is being caught as a empty line to my string variable? I thought that fail() should stop the loop and leave me with correct output?
as long as you have names which don't contain white spaces and age as integer then you can read name as a string and age as an integer.
you don't need to check whether the file was successfully opened or not you can just abbreviate the operation:
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::ifstream file;
std::string word;
int age;
file.open("data.txt");
while( file >> word)
{
file >> age;
std::cout << word << " " << age << std::endl;
}
std::cout << std::endl;
return 0;
}
if you want to use one variable and for sure a string one then:
while( file >> word)
{
std::cout << word << " ";
file >> word;
std::cout << word << std::endl;
}
I don't see any good thing to read age as a string and maybe later convert it back to an integer!
the output:
Arthur 20
Mark 21
Josh 12

Example for file input to structure members?

I have the following structure:
struct productInfo
{
int item;
string details;
double cost;
};
I have a file that will input 10 different products that each contain an item, details, and cost. I have tried to input it using inFile.getline but it just doesn't work. Can anyone give me an example of how to do this? I would appreciate it.
Edit
The file contains 10 lines that look like this:
570314,SanDisk Sansa Clip 8 GB MP3 Player Black,55.99
Can you provide an example please.
Edit
Sorry guys, I am new to C++ and I don't really understand the suggestions. This is what I have tried.
void readFile(ifstream & inFile, productInfo products[])
{
inFile.ignore(LINE_LEN,'\n'); // The first line is not needed
for (int index = 0; index < 10; index++)
{
inFile.getline(products[index].item,SIZE,DELIMETER);
inFile.getline(products[index].details,SIZE,DELIMETER);
inFile.getline(products[index].cost,SIZE,DELIMETER);
}
}
This is another approach that uses fstream to read the file and getline() to read each line on the file. The parsing of the line itself was left out on purpose since other posts have already done that.
After each line is read and parsed into a productInfo, the application stores it on a vector, so all products could be accessed in memory.
#include <iostream>
#include <fstream>
#include <vector>
#include <iterator>
#include <string>
using namespace std;
struct productInfo
{
int item;
string details;
double cost;
};
int main()
{
vector<productInfo> product_list;
ifstream InFile("list.txt");
if (!InFile)
{
cerr << "Couldn´t open input file" << endl;
return -1;
}
string line;
while (getline(InFile, line))
{ // from here on, check the post: How to parse complex string with C++ ?
// https://stackoverflow.com/questions/2073054/how-to-parse-complex-string-with-c
// to know how to break the string using comma ',' as a token
cout << line << endl;
// productInfo new_product;
// new_product.item =
// new_product.details =
// new_product.cost =
// product_list.push_back(new_product);
}
// Loop the list printing each item
// for (int i = 0; i < product_list.size(); i++)
// cout << "Item #" << i << " number:" << product_list[i].item <<
// " details:" << product_list[i].details <<
// " cost:" << product_list[i].cost << endl;
}
EDIT: I decided to take a shot at parsing the line and wrote the code below. Some C++ folks might not like the strtok() method of handling things but there it is.
string line;
while (getline(InFile, line))
{
if (line.empty())
break;
//cout << "***** Parsing: " << line << " *****" << endl;
productInfo new_product;
// My favorite parsing method: strtok()
char *tmp = strtok(const_cast<char*>(line.c_str()), ",");
stringstream ss_item(tmp);
ss_item >> new_product.item;
//cout << "item: " << tmp << endl;
//cout << "item: " << new_product.item << endl;
tmp = strtok(NULL, ",");
new_product.details += tmp;
//cout << "details: " << tmp << endl;
//cout << "details: " << new_product.details << endl;
tmp = strtok(NULL, " ");
stringstream ss_cost(tmp);
ss_cost >> new_product.cost;
//cout << "cost: " << tmp << endl;
//cout << "cost: " << new_product.cost << endl;
product_list.push_back(new_product);
}
It depends on what's in the file? If it's text, you can use the redirect operator on a file input stream:
int i;
infile >> i;
If it's binary, you can just read it in to &your_struct.
You have to
0) Create a new instance of productInfo, pinfo;
1) read text (using getline) to the first comma (','), convert this string to an int, and put it into pinfo.item.
2) read text to the next comma and put it into pinfo.details;
3) read text to the endline, convert the string to a double, and put it into pinfo.cost.
Then just keep doing this until you reach the end of the file.
Here is how I would use getline. Note that I use it once to read from the input file, and then again to chop that line at ",".
ostream& operator>>(istream& is, productInfo& pi)
{
string line;
getline(is, line); // fetch one line of input
stringstream sline(line);
string item;
getline(sline, item, ',');
stringstream(item) >> pi.item; // convert string to int
getline(sline, item, ',');
pi.details = item; // string: no conversion necessary
getline(sline, item);
stringstream(item) >> pi.cost; // convert string to double
return is;
}
// usage:
// productInfo pi; ifstream inFile ("inputfile.txt"); inFile >> pi;
N.b.: This program is buggy if the input is
99999,"The Best Knife, Ever!",16.95