There are a few problems with the code you've shown.
operator>>
opens the file every time and ignores the stream that is passed in. This will always read the first line from the file.
- Mixing
std::getline
and >>
when reading from the file is messy. See Why does std::getline() skip input after a formatted extraction? for more details.
- The lines using
>>
won't work for two reasons. You need to use std::boolalpha
to read the words true
and false
, and there's a semicolon between them which is definitely not a bool
and would cause an error.
Here's an example I put together on ideone
It writes a test file using the data you supplied and an extra line with made up data to verify that "false; true" reads correctly since both of your lines had "true; false".
It opens the file and reads the data into a book
structure that should resemble yours using operator>>
and adds it to a vector.
It writes the data from the vector to std::cout
using operator<<
in the same semicolon delimited format.
I added some code from another answer to trim the strings that are read since there was a space after the semicolon in the data shown and I'm pretty sure you do not want that kept when the data is read in.
I used std::getline
exclusively to avoid issues and assigned the boolean values using a simple string comparison, if the string matches "true" the bool is true and otherwise it is false. You may want something more robust like forcing the string to lowercase first. It'll depend on how confident you are about your input data.
The last getline
does not include the delimiter so it will read properly since the lines do not end with a semicolon. This will work on well formatted input data. You might consider a more robust solution of reading the whole line then splitting it, making sure it has the right number of tokens, and then assigning to the book. There are plenty of examples on here of how to split strings if you need them.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
//---
// Borrowed trim from https://stackoverflow.com/a/217605/920069
#include <algorithm>
#include <cctype>
#include <locale>
// trim from start (in place)
static inline void ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return !std::isspace(ch);
}));
}
// trim from end (in place)
static inline void rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return !std::isspace(ch);
}).base(), s.end());
}
// trim from both ends (in place)
static inline void trim(std::string &s) {
rtrim(s);
ltrim(s);
}
//---
struct book
{
std::string title;
std::string author;
std::string genre;
std::string ISBN;
bool br;
bool av;
friend std::istream& operator>>(std::istream& in, book& b)
{
if (getline(in, b.title, ','))
{
trim(b.title);
}
if (getline(in, b.author, ','))
{
trim(b.author);
}
if (getline(in, b.genre, ','))
{
trim(b.genre);
}
if (getline(in, b.ISBN, ','))
{
trim(b.ISBN);
}
std::string temp;
if (getline(in, temp, ','))
{
trim(temp);
b.av = (temp == "true");
}
if (getline(in, temp))
{
trim(temp);
b.br = (temp == "true");
}
return in;
}
friend std::ostream& operator<<(std::ostream& out, const book& b)
{
out << b.title << "; ";
out << b.author << "; ";
out << b.genre << "; ";
out << b.ISBN << "; ";
// If strem is still good save and restore the flags
// because boolalpha is persistent
if (out)
{
std::ios_base::fmtflags flags = out.flags();
out << std::boolalpha;
out << b.av << "; ";
out << b.br << '\n';
out.flags(flags);
}
return out;
}
};
void createTestFile()
{
std::ofstream f("test.txt");
if (!f)
{
std::cerr << "Error creating file!\n";
exit(-1);
}
f << "1.The Alchemist, Paulo Coelho, Fiction, 978-0-06-112073-3, true, false\n";
f << "2.The Lord of the Rings, J.R.R. Tolkien, Fantasy, 978-0-345-39195-8, true, false\n";
f << "3.Made Up Book, Some Guy, Pulp, 999-0-888-7777-8, false, true\n";
}
int main()
{
createTestFile();
std::ifstream f("test.txt");
if (!f)
{
std::cerr << "Error opening file!\n";
exit(-1);
}
book b;
std::vector<book> v;
while (f >> b)
{
v.push_back(b);
}
for (const book& b : v)
{
std::cout << b;
}
}
Hopefully this will help you put together a solution that works for you. If you have questions please ask.