-1

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?

A.Petrov
  • 71
  • 6
  • 2
    getline 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
  • 2
    What 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
  • 2
    Please 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 Answers2

2

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
Justin Randall
  • 1,981
  • 2
  • 12
  • 18
-3
#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
    }
}
Mateusz Wojtczak
  • 1,503
  • 9
  • 25
  • 1
    No. 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