Wrong reading of text file in c++ - c++

I just want to read a text file and store the data into a vector. Thereby the value weight should be sum till the limit is reached. The first four lines will be read correctly but the following will not read. What is the mistake?
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <limits>
/*
Data.txt
John
6543
23
Max
342
2
A Team
5645
23
*/
struct entry
{
// passengers data
std::string name;
int weight; // kg
std::string group_code;
};
void reservations()
{
std::ofstream file;
file.clear();
file.open("reservations.txt");
file.close();
}
entry read_passenger(std::ifstream &stream_in)
{
entry passenger;
if (stream_in)
{
std::getline(stream_in, passenger.name);
stream_in >> passenger.weight;
std::getline(stream_in, passenger.group_code);
stream_in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
return passenger;
}
return passenger;
}
int main(void)
{
std::ifstream stream_in("data.txt");
std::vector<entry> v; // contains the passengers data
const int limit_total_weight = 10000; // kg
int total_weight = 0; // kg
entry current;
while (!stream_in.eof())
{
current = read_passenger(stream_in);
total_weight = total_weight + current.weight;
std::cout << current.name << std::endl;
if (total_weight >= limit_total_weight)
{
break;
}
}
return 0;
}

These two lines,
std::getline(stream_in, passenger.group_code);
stream_in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
should be in the opposite order:
stream_in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::getline(stream_in, passenger.group_code);
Think about what the purpose of the ignore is.
Also, instead of checking only for EOF, check for general error.
I.e., instead of
while (!stream_in.eof())
write
while (stream_in)
Maybe there's more wrong, but the above is what I saw immediately.
Cheers & hth.,

I try not to mix formatted and line-oriented input for precisely this reason. If it were me, and I had to use getline anywhere, I would use getline everywhere:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <limits>
#include <sstream>
struct entry
{
// passengers data
std::string name;
int weight; // kg
std::string group_code;
};
void reservations()
{
std::ofstream file;
file.clear();
file.open("reservations.txt");
file.close();
}
std::istream& operator>>(std::istream& stream_in, entry& passenger)
{
std::getline(stream_in, passenger.name);
std::string weightString;
std::getline(stream_in, weightString);
std::istringstream (weightString) >> passenger.weight;
std::getline(stream_in, passenger.group_code);
return stream_in;
}
void read_blankline(std::istream& stream_in) {
std::string blank;
std::getline(stream_in, blank);
}
int main(void)
{
std::ifstream stream_in("data.txt");
std::vector<entry> v; // contains the passengers data
const int limit_total_weight = 10000; // kg
int total_weight = 0; // kg
entry current;
while (stream_in >> current)
{
total_weight = total_weight + current.weight;
std::cout << current.name << std::endl;
if (total_weight >= limit_total_weight)
{
break;
}
read_blankline(stream_in);
}
return 0;
}

Related

C++ program to perform operations using a text file

item,price,qty,ordno,trdno
abc,54,2,123,32
xyz,34,2,345,21
item: string (char[])
price,qty (int)
ordno (long long)
trdno (int)
Make a structure for above mentioned fields
Make a vector (array, or any other container type) to hold multiple instances of this structure
1: Read file
2: read line, split values
3: initialize above mentioned structure object
4: add this object of structure to container
5: when whole file is read.. iterate over the container and print each elements values (serialno, orderno, tradeno, price, qty, item)
I tried this and it is not working-
#include<bits/stdc++.h>
using namespace std;
struct item {
string name;
double price;
int quantity;
int order_no;
int trd_no;
};
int main()
{
int n;cin>>n;
string str, T;
ifstream read("input.txt");
while(getline(read,str))
{
cout<<str<<endl;
}
stringstream X(str); // X is an object of stringstream that references the S string
cout<<endl;
while (getline(X, T, ','))
{
cout << T << endl; // print split string
}
read.close();
return 0;
}
For the code that you are showing, you misplaced just one '}' after the first while. So the code will read in the first while-loop all lines of the file and is then empty. And, then you try to split the lines. This can of course not work.
If you move the closing bracket to in front of read.close(); then your code will work. Like this:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
using namespace std;
struct item {
string name;
double price;
int quantity;
int order_no;
int trd_no;
};
int main()
{
int n; cin >> n;
string str, T;
ifstream read("input.txt");
while (getline(read, str))
{
cout << str << endl;
stringstream X(str); // X is an object of stringstream that references the S string
cout << endl;
while (getline(X, T, ','))
{
cout << T << endl; // print split string
}
}
read.close();
return 0;
}
Caveat: this will not work, if the source file contains the header row! You can read this and throw it away, if needed.
If we follow the instruction of your homework, line by line, and assume that the first line contains header rows, then we would do like the following.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
struct Item {
std::string name;
double price;
int quantity;
long long order_no;
int trd_no;
};
int main()
{
std::vector<Item> items;
std::string str, T;
std::ifstream read("input.txt");
// Read first line and ignore it
std::getline(read, str);
while (std::getline(read, str))
{
std::istringstream X(str);
Item tempItem;
getline(X, T, ',');
tempItem.name = T;
getline(X, T, ',');
tempItem.price = std::stod(T);
getline(X, T, ',');
tempItem.quantity = std::stoi(T);
getline(X, T, ',');
tempItem.order_no = std::stoll(T);
getline(X, T, ',');
tempItem.trd_no = std::stoi(T);
items.push_back(tempItem);
}
read.close();
for (const Item& item : items)
std::cout << item.name << ' ' << item.price << ' ' << item.quantity << ' '
<< item.order_no << ' ' << item.trd_no << '\n';
}
And, with a little bit more advanced C++, where we especially keep data and methods in a class, we could do the following:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <iomanip>
#include <algorithm>
#include <iterator>
// The item
struct Item {
std::string name{};
double price{};
int quantity{};
long long order_no{};
int trd_no{};
// Overwrite extraction operator for easier stream IO
friend std::istream& operator >> (std::istream& is, Item& i) {
char c;
return std::getline(is >> std::ws, i.name, ',') >> i.price >> c >> i.quantity >> c >> i.order_no >> c >> i.trd_no;
}
// Overwrite inserter for easier output
friend std::ostream& operator << (std::ostream& os, const Item& i) {
return os << "Name: " << i.name << "\tPrice: " << i.price << "\tQuantity: " << i.quantity << "\tOrder no: " << i.order_no << "\tTRD no: " << i.trd_no;
}
};
// The Container
struct Data {
std::vector<Item> items{};
// Overwrite extraction operator for easier stream IO
friend std::istream& operator >> (std::istream& is, Data& d) {
// Read header line and ignore it
std::string dummy; std::getline(is, dummy);
// Delete potential old data
d.items.clear();
// Read all new data from file
std::copy(std::istream_iterator<Item>(is), {}, std::back_inserter(d.items));
return is;
}
// Overwrite inserter for easier output
friend std::ostream& operator << (std::ostream& os, const Data& d) {
std::copy(d.items.begin(), d.items.end(), std::ostream_iterator<Item>(os, "\n"));
return os;
}
};
int main()
{
// Open file and check, if it could be opened
if (std::ifstream sourceFileStream("input.txt"); sourceFileStream) {
// Define container
Data data{};
// Read and parse complete source file and assign to data
sourceFileStream >> data;
// Show result
std::cout << data;
}
else std::cerr << "\n\nError: Could not open source file:\n\n";
}

How can I compare the third token from each line using 'getline()'?

Input file: In each row, there's an entry that is a pair of ID - name - GPA. Values are tab-delimited.
20210001 Bill 3.61
20210002 Joe 3.21
20210003 Royce 4.32
20210004 Lucy 2.21
I have to rearrange this file sorted by the GPA (in decreasing order).
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
int main() {
ifstream inputfile("input.txt");
ofstream outputfile("output.txt");
if (inputfile.fail()) {
cout << "Cannot open inputfile" << endl;
}
if (outputfile.fail()) {
cout << "Cannot open outputfile" << endl;
}
if (inputfile.is_open()) {
string line;
while (getline(inputfile, line)) {
string token;
stringstream ss(line);
while (getline(ss, token, '\t')) {
}
}
}
inputfile.close();
outputfile.close();
return 0;
}
I'm not sure what to do next.
When doing I/O from/to streams (like file streams) it usually makes it easier to create a class to keep the data for each record in the file and to create overloads for operator>> (in) and operator<< (out).
Example:
#include <algorithm>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
// one line in the file could possibly have this representation in your program:
struct record {
std::uint32_t ID;
std::string name;
double GPA;
};
// an overload to read one line of data from an istream (like an ifstream) using getline
std::istream& operator>>(std::istream& is, record& r) {
if(std::string line; std::getline(is, line)) {
std::istringstream iss(line);
if(not (iss >> r.ID >> r.name>> r.GPA)) {
is.setstate(std::ios::failbit);
}
}
return is;
}
// an overload to write one line to an ostream (like an ofstream)
std::ostream& operator<<(std::ostream& os, const record& r) {
return os << r.ID<< '\t' << r.name << '\t' << r.GPA << '\n';
}
With that boilerplate in place, making the actual program becomes easy.
int main() {
std::ifstream inputfile("input.txt");
// read all records from the file into a vector
std::vector<record> records(
std::istream_iterator<record>(inputfile),
std::istream_iterator<record>{}
);
// sort the records according to GPA
// if you want a decending order, just make it return rhs.GPA < lhs.GPA;
std::sort(records.begin(), records.end(),
[](const record& lhs, const record& rhs) {
return lhs.GPA < rhs.GPA;
}
);
std::ofstream outputfile("output.txt");
// put the result in the output file
std::copy(records.begin(),
records.end(),
std::ostream_iterator<record>(outputfile));
}
There may be a few things in this answer that you haven't seen before. I'll list resources for those I anticipate may require some reading:
operator<< / operator>> overloading. See Stream extraction and insertion
std::istringstream - You put a std::string in it - and then it behaves like any other std::istream (like a std::ifstream).
std::istream_iterator/std::ostream_iterator
std::sort / std::copy are two of the many algorithms in the standard library.
std::vector - A class template acting as a dynamic array where you can add and remove data, like record in this answer.
Lambda expressions - In this answer it's the functor [](const record& lhs, const record& rhs) { ... } used to sort the records.
If you know exactly how many tokens are in a line:
You could simply getline() 3 times with the tab delimiter, and store the values separately.
string id;
string name;
string gpa;
getline(ss, id, '\t');
getline(ss, name, '\t');
getline(ss, gpa, '\t');
This logic would live within your loop that iterates over the lines in the file.
You could use a struct to contain all your fields:
struct user
{
int id; string name; double point;
};
Then insert all of them into a std::vector and finally use sort() with the comp parameter to sort by points.
Code:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <algorithm>
#include <iomanip>
using namespace std;
struct user
{
int id; string name; double point;
};
vector<user> users;
void stripInfoFromString(string inp)
{
stringstream cur(inp);
user curUser;
cur >> curUser.id >> curUser.name >> curUser.point;
users.push_back(curUser);
}
bool compareUser(user x, user y)
{
return x.point < y.point;
}
int main()
{
string a1 = "20210001 Bill 3.61";
string a2 = "20210002 Joe 3.21";
string a3 = "20210003 Royce 4.32";
string a4 = "20210004 Lucy 2.21";
stripInfoFromString(a1);
stripInfoFromString(a2);
stripInfoFromString(a3);
stripInfoFromString(a4);
sort(users.begin(), users.end(), compareUser);
cout << fixed << setprecision(2);
for (user cur : users)
{
cout << cur.id << " " << cur.name << " " << cur.point << "\n";
}
}
Output:
20210004 Lucy 2.21
20210002 Joe 3.21
20210001 Bill 3.61
20210003 Royce 4.32
I used standard input/output to minimize the code, you can simply switch for file inputs easily.
More info:
struct : https://en.cppreference.com/w/c/language/struct
sort() : https://en.cppreference.com/w/cpp/algorithm/sort
Also, see here why is using namespace std; considered bad practice.
I would suggest defining a struct to hold the 3 tokens, and then create a std::vector holding instances of that struct for each line. You can then sort that vector on the 3rd token. You already have <vector> in your header includes.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
struct entry
{
int id;
string name;
double gpa;
};
int main() {
ifstream inputfile("input.txt");
ofstream outputfile("output.txt");
vector<entry> entries;
if (inputfile.fail()) {
cout << "Cannot open inputfile" << endl;
}
if (outputfile.fail()) {
cout << "Cannot open outputfile" << endl;
}
string line;
while (getline(inputfile, line)) {
istringstream iss(line);
entry e;
string token;
getline(iss, token, '\t');
e.id = stoi(token);
getline(iss, e.name, '\t');
getline(iss, token, '\t');
e.gpa = stod(token);
/* alternatively:
iss >> e.id >> e.name >> e.gpa;
*/
entries.push_back(e);
}
inputfile.close();
outputfile.close();
sort(entries.begin(), entries.end(),
[](const entry &e1, const entry &e2){
return e1.gpa > e2.gpa;
}
);
for (const entry &e : entries) {
outputfile << e.id << '\t' << e.name << '\t' << e.gpa << '\n';
}
return 0;
}
Demo

Vectors in C++ Files

Within this function, I am passing multiple files. It was implemented with arrays before, and now I need to convert all of the arrays to vectors. The issue I have is when I read in from the files, it does not stop. Why??
void readIn(ifstream &iFile, vector<string> &itemName, vector<double> &itemPrice, vector<double> &quantity)
{
int x = 0;
string str;
string nTemp;
double pTemp;
int qTemp;
while(!iFile.eof())
{
getline(iFile, nTemp);
iFile.ignore();
itemName.push_back(nTemp);
iFile >> pTemp;
itemPrice.push_back(pTemp);
iFile >> qTemp;
quantity.push_back(qTemp);
cout << itemName.size() << " " << itemPrice.size() << " " << quantity.size() << endl;
}
readIn(appIn, appName, appPrice, appquantity);
readIn(drinkIn, drinkName, drinkPrice, driquantity);
readIn(entreeIn, entreeName, entreePrice, entquantity);
readIn(dessertIn, desName, desPrice, dessquantity);
This is the function and calls. Not sure why when outputting the item name, item price and quantity sizes, it just continually reads in values.
Expanding your code to an executable example:
#include <vector>
#include <string>
#include <fstream>
#include <iostream>
using namespace std;
void readIn(ifstream &iFile, vector<string> &itemName, vector<double> &itemPrice,
vector<double> &quantity)
{
int x = 0;
string str;
string nTemp;
double pTemp;
int qTemp;
while(!iFile.eof())
{
getline(iFile, nTemp);
iFile.ignore();
itemName.push_back(nTemp);
iFile >> pTemp;
itemPrice.push_back(pTemp);
iFile >> qTemp;
quantity.push_back(qTemp);
cout << itemName.size() << " " << itemPrice.size() << " " << quantity.size()
<< endl;
}
}
int main () {
vector<string> nam;
vector<double> price,quantity;
ifstream in;
in.open("data_adamp.txt");
readIn(in,nam,price,quantity);
}
Given ...
$ cat data_adamp.txt
animal a 1 2
beach b 3 4
cart c 4 5
dog d 6 7
... compiling with (GCC version 6.4.0):
$ gcc adamp.cpp -lstdc++ -oadamp
... lets me run:
$ ./adamp
... which does indeed never stop.
One way to solve this problem is to tokenize each line and convert the two rightmost fields to doubles and the rest to the record name, e.g. (using the approach in the highest-ranked answer to How do I iterate over the words of a string?):
#include <vector>
#include <string>
#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>
#include <iterator>
using namespace std;
// See the highest-scoring answer to https://stackoverflow.com/questions/236129/how-do-i-iterate-over-the-words-of-a-string/236803#236803
template<typename Out>
void split(const std::string &s, char delim, Out result) {
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim)) {
*(result++) = item;
}
}
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> elems;
split(s, delim, std::back_inserter(elems));
return elems;
}
void readIn(ifstream &iFile, vector<string> &itemName, vector<double> &itemPrice,
vector<double> &quantity)
{
string nTemp;
double pTemp;
int qTemp;
string line;
while(getline(iFile,line))
{
char delim = ' ';
vector<string> s = split(line,delim);
istringstream ss;
ss.str(s.back());
ss >> qTemp;
s.pop_back();
ss.str(s.back());
ss.clear();
ss >> pTemp;
s.pop_back();
nTemp = "";
for (int i = 0; i < s.size(); i++)
{
if (i > 0) nTemp.append(" ");
nTemp.append(s[i]);
}
itemName.push_back(nTemp);
itemPrice.push_back(pTemp);
quantity.push_back(qTemp);
cout << nTemp << "++" << pTemp << "++" << qTemp << endl;
}
}
int main () {
vector<string> nam;
vector<double> price,quantity;
ifstream in;
in.open("data_adamp.txt");
readIn(in,nam,price,quantity);
}

error with reading data back out of a vector

this is my program for reading data from a text file and storing it into a vector, im having trouble compiling this, any suggesting would be great.
id like to in this example to call all the data for year and month.
im hoping its something simple ive missed.
#include <iostream>
#include <libscat.h>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
struct Weather
{
int year;
int month;
double tempmax;
double tempmin;
};
int main()
{
vector<Weather> data_weather;
string line;
std::ifstream myfile ("weatherdata.txt");
if (myfile.is_open())
{
while ( getline(myfile, line) )
{ int count = 0;
if (count > 8)
{
std::istringstream buffer(line);
int year, mm;
double tmax, tmin;
if (buffer >> year >> mm >> tmax >> tmin)
{
Weather objName = {year, mm, tmax, tmin};
data_weather.push_back(objName);
count++;
}
}
for (auto it = data_weather.begin(); it != data_weather.end(); it++){
std::cout << it->year << " " << it->month << std::endl;}
myfile.close();
}
else
{
cout << "unable to open file";
}
scat::pause("\nPress <ENTER> to end the program.");
return 0;
}
}
Here's a fixed version with explanation since there still wasn't any real answer.
#include <iostream>
#include <libscat.h>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
struct Weather
{
int year;
int month;
double tempmax;
double tempmin;
};
int main()
{
std::vector<Weather> data_weather;
std::string line;
std::ifstream myfile("weatherdata.txt");
if (myfile.is_open())
{
int count = 0; // you gotta put it in front of the while loop or you'll
// create a new variable and initialize it to 0 every time
// you enter the loop
while ( getline(myfile, line) )
{
// int count = 0; // placed it just before the loop
if ( count > 8)
{
std::istringstream buffer(line);
int year, mm;
double tmax, tmin;
if (buffer >> year >> mm >> tmax >> tmin)
{
Weather objName = {year, mm, tmax, tmin};
data_weather.push_back(objName);
// count++; // you're still inside the if (count > 8)
// you'd probably want to have it outsided the if statement
// instead.
}
}
++count; //the count from inside. it'll probably do what you wanted
//it to do here.
// you'll probably want to run the for loop AFTER the while loop
// when the data_weather vector got fully filled
}
// the for loop from inside the while now outside
for (auto it = data_weather.begin(); it != data_weather.end(); ++it)
{
std::cout << it->year << " " << it->month << std::endl;
myfile.close();
}
}
else
{
std::cout << "unable to open file";
}
scat::pause("\nPress <Enter> to end the program.");
return 0;
}

C++ Reading ints and strings from file

I have a file that looks like :
4
Sam Stone
2000
Freida Flass
100500
Tammy Flass
5000
Rich Raptor
55000
I am trying to read from it, but the first getline in the while loop always returns nothing. The int 4 gets read correctly.
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <vector>
#include <string>
using namespace std;
const int SIZE = 60;
struct person
{
string name;
double money;
};
int main()
{
char filename[SIZE];
string input;
char inputs [50];
int value;
int count = 0;
vector<person> Members;
ifstream inFile;
inFile.open("carinfo.txt");
if (!inFile.is_open()){ cout << "Could not open fle"; }
inFile >> value;
Members.resize(value);
while (inFile.good())
{
inFile.getline(inputs, SIZE); //getline(inFile, input, '\n');
inFile >> value;
count++;
}
cout << "Total lines = " << count;
system("pause");
return 0;
}
Consider using std::string and op>>(std::istream, person) to read the elements, this works for me
#include <string>
#include <vector>
#include <limits>
#include <fstream>
#include <iostream>
#include <iterator>
struct person
{
std::string name;
double money;
};
//read in 1 person
std::istream& operator>>(std::istream& is, person& p) {
is >> p.money;
is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::getline(is, p.name);
return is;
}
int main() {
//open stream
std::ifstream file("fname");
//create vector, let the stream operators do the hard work
std::vector<person> v((std::istream_iterator<person>(file)),
std::istream_iterator<person>());
std::cout << "count: " << v.size();
}
http://en.cppreference.com/w/cpp/iterator/istream_iterator