I want to read books - their title, author and price from a txt file. The 3 properties of the book are separated by '|' - Title|Author|Book.
However, I do not know exactly how to do this. I have the structure Book, with 3 elements. I want, for each line to read the book title, author and price, save them to the 3 variables of the structure respectively and print them on the console. I have tried to do this with the title only, but it print the whole line. I would like to ask how can I print for each books separately its author title and price?
![](../../users/profiles/9263993.webp)
- 71
- 6
-
2getline will read the entire line. After that, you need to parse it dependent on the format of your lines. – Anon Mail Feb 26 '18 at 15:49
-
3`while(!p.eof()){` https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong – drescherjm Feb 26 '18 at 15:50
-
2What is the benefit of using `ptstr`? Why not simply use `a.title`? – xskxzr Feb 26 '18 at 15:51
-
***However, I do not know exactly how to do this.*** It depends on how the file is written. How do you separate the 3 different items on a line? – drescherjm Feb 26 '18 at 15:51
-
There are quite a few tutorials online, and of course you should get [a good beginners book or two](https://stackoverflow.com/a/388282/440558) to read. – Some programmer dude Feb 26 '18 at 15:52
-
3`getline` has two main uses: `getline(stream, line)` to get a line and `getline(stream, token, delimiter)` to get a token. Put a `std::stringstream` into the mix to allow you to parse the line as a stream and you're pretty much done. – user4581301 Feb 26 '18 at 16:01
-
2Please do not rush into accepting an answer. The one posted below, that you have already accepted, is wrong. – Lightness Races in Orbit Feb 26 '18 at 16:34
-
This issue is similar to reading CSV (Comma Separated Values) format, except you are using '|' instead of ','. Please search the internet for "c++ read file CSV" for examples. – Thomas Matthews Feb 26 '18 at 16:40
-
Do you mean `Title|Author|Price`? Can you post a sample of the input file format? – Justin Randall Feb 26 '18 at 16:55
2 Answers
The include libraries you will need, and your Book
structure definition. Once you get to study slightly more advanced C++ topics you could learn how to overload friend functions for input and output streams to make your I/O operations self-contained for a Book
object.
#include <iostream> ///< std::cout
#include <fstream> ///< std::ifstream
#include <sstream> ///< std::istringstream, std::string
#include <vector> ///< std::vector
struct Book
{
std::string title; ///< title of the book
std::string author; ///< author of the book
std::string price; ///< price of the book (TODO use float instead?)
// TODO consider friend std::istream& operator>> for parsing input data
// TODO consider friend std::ostream & operator<< for printing object
};
If you have a handle to your input file you could parse it like this. Read each line at a time. Do not read until input.eof() because it's wrong! Store each line into a temporary std::istringstream
object for further parsing. Use the overloaded std::getline(stream, token, delimiter)
with |
to parse the data in the line, and save them directly into your temporary Book
object. Finally, store the object into your vector if you want to be able to process them later, and optionally print them to the console.
void readBooks(std::ifstream& input, std::vector<Book>& books)
{
std::string line;
while (std::getline(input, line)) ///< while we have a line to parse
{
std::istringstream iss(line); ///< line to parse as sstream
Book book; ///< temporary book object
std::getline(iss, book.title, '|');
std::getline(iss, book.author, '|');
std::getline(iss, book.price, '|');
books.push_back(book); ///< add book object into vector
std::cout << "Title: " << book.title << std::endl;
std::cout << "Author: " << book.author << std::endl;
std::cout << "Price: " << book.price << std::endl << std::endl;
}
}
int main()
{
std::vector<Book> books; ///< store each Book object
std::ifstream input("books.txt");
if (input.is_open())
{
readBooks(input, books); ///< read your books
}
return 0;
}
Tested with the following input file contents
Tales from Shakespeare (1807)|Shakespeare|6.74 The Jungle Book (1894)|Rudyard Kipling|9.99 Through the Looking-Glass (1871)|Lewis Carroll|12.97
Yielded the following results
Title: Tales from Shakespeare (1807) Author: Shakespeare Price: 6.74 Title: The Jungle Book (1894) Author: Rudyard Kipling Price: 9.99 Title: Through the Looking-Glass (1871) Author: Lewis Carroll Price: 12.97
![](../../users/profiles/2096824.webp)
- 1,981
- 2
- 12
- 18
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
struct Book {
string title;
string author;
string price;
};
void read_Books(std::ifstream&, Book&);
int main()
{
ifstream p("books.txt", ios::in);
Book a;
read_Books(p, a);
return 0;
}
void read_Books(std::ifstream& p, Book& ptstr) {
while(p.is_open() && !p.eof()){
getline(p, ptstr.title, '|');
getline(p, ptstr.author, '|');
getline(p, ptstr.price, '|');
cout<<ptstr.title << ptstr.author << ptstr.price << std::endl;
//The whole line is printed, it ought to be the title only
}
}
![](../../users/profiles/3655463.webp)
- 1,503
- 9
- 25
-
1No. That is not how to read from a stream in a loop. Please read https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong, several times. – Lightness Races in Orbit Feb 26 '18 at 16:34
-
And what exactly is the point of passing in a reference to a `Book` object if you're just going to be overwriting it again and again? Maybe a reference to a `std::vector
` would make more sense here? – Justin Randall Feb 26 '18 at 16:57