I have designed a linklist based BookStore in which book's attributes will be stored in a node & so on. Plus at the end of program, I have to save all database into text file (I tried binary reading but damn I got me killed & couldn't do it) & then reload all info, of each book one by one & store it in nodes & re-make the LinkList.

Now saving is done & no issue at all.
But Im having issues in reading from text file.

Saving structure in file is:::

BookID(int) - BookName(string) - Author(string) - BookType(string) - Copies(long) - Price(long) - '\n' (to go to next line)

EXAMPLE:
1 ObjectOrientedParadigm R.Lafore Coding 5 900
2 ObjectOrientedParadigm R.Lafore Coding 5 900
and so on......

Here is the saving function.

bool BookStoreDataBase<mytype>::save_all_data()
{
    if(!is_Empty()) //if list is not empty
    {
        BOOK<mytype> *temp = head;   //created a copy of head
        ofstream file("database.txt", ios_base::app); //created file, to write at the end (append)
        while(temp != tail) //while list ends
        {
            file<<temp->ID<<' '<<temp->bookName<<' '<<temp->author<<' '<<temp->book_type<<' '<<temp->copies<<' '<<temp->price<<' ';  //write all info
            temp = temp->next; //move temp to next node
        }
        file<<temp->ID<<' '<<temp->bookName<<' '<<temp->author<<' '<<temp->book_type<<' '<<temp->copies<<' '<<temp->price<<' '; //for last book's info
        return true; //to confirm sucessfull writing
    }
    else //if list is empty
    {
        return false; //to confirm error in writing
    }
}

PROBLEM:: When I start reading, first line is read fine & stored in list, but for the next time, I can't make file to read from the next line, hence '\n'. & that creates the problem. File again reads the first line & 2nd node is created with same data.

Loading Function:

void BookStoreDataBase<mytype>::load_all_data()
{
    int ID;         //variable to store ID of a book
    string bookName;//string to store name of a book
    string author;  //string to store name of author of book
    string book_type;//string to store type of a book
    long copies;    //variable to store no. of copies a book
    long price;     //variable to store price of a book
    string status;  //to store status of a book, either its in stock or not


    ifstream file("database.txt");
    while(file) //I have tried file.eof but its not working, don't know why
    {
        file>>ID>>bookName>>author>>book_type>>copies>>price>>status; //read file

        BOOK<mytype> *temp = new BOOK<mytype>(0, 0, bookName, author, book_type, copies, price);  //create a new node in memory and save all the data

        if(is_Empty()) //if list is empty, then make 1st node
        {
            head = tail = temp;
        }
        else //other wise make the next node
        {
            tail->next = temp;
            temp->prev = tail;
            tail = temp;
        }
    }
}

MOREOVER
Reading is done 1 time less than the real record. i.e. If .txt has record of 4 books, then 3 nodes are created, (& info of only 1st is repeated in every node), whereas it should read & create 4 nodes!

Im a beginner, any good help will be much appreciated. Luv All!

Edited 3 Years Ago by mike_2000_17: Fixed formatting

In the read function, the loop should look like below. If that doesn't fix the problem then I suspect the problem is in the BOOK class constructor. You need to post it.

while( file>>ID>>bookName>>author>>book_type>>copies>>price>>status)
{

}

Edited 4 Years Ago by Ancient Dragon

It's advisable not to use file.eof() because the stream only signals EOF when it reaches the very end of the file. So if there's an empty line or if there's extra whitespace at the very last element, the stream still considers data to be read.

For example,

inputData.txt
----------------------
1 field1 field2 field3
2 field1 field2 field3
3                       <-- newline, eof() will not be true after reading line 2
----------------------

inputData2.txt
----------------------
1 field1 field2 field3
2 field1 field2 field3<space><tab>  <-- any kind of whitespace at the end will lead to the same problem
----------------------

The best way to read data from a text file is to read the entire line and convert it to a stringstream for easy extraction. You should read more about stringstream if you don't know about it yet. In simple terms, a stringstream is a class that treats a string like an input/output stream. So the string acts like a file stream and you could use extraction >> and insertion << operations on them.

// Declare a stringstream
stringstream ss;

// Read each line (ends with newline)
while (getline(infile, line, 'n'))
{
    lines++;

    ss.clear();     // you should call this to clear any error flags that could be
                    // set during IO operations
    ss.str(line);   // treat the string as a stream 

    // extract the data from our stringstream and store in the appropriate variables
    ss >> ID >> bookName >> author >> book_type >> copies >> price >> status;
}

I would also recommend checking for IO errors that result from invalid file format, such as missing a field or incorrect field format.

// extract the data from our stringstream and store in the appropriate variables
ss >> ID >> bookName >> author >> book_type >> copies >> price >> status;

// check for invalid format of fields, or lack of fields
if (ss.fail()) {
    cerr << "Failed to read data on line " << lines << endl;
}

Edited 4 Years Ago by dx9_programmer

@ Ancient Dragon:
No that didn't solve.
Here is the constructor of BOOK

template<class mytype>
    class BOOK      //template type BOOK class
    {
    private:
        static int count;   //declaration of static variable to set ID for books, to be defined outside class
    public:
        BOOK<mytype> *next, *prev;   //BOOK type pointers; 'next' to store address of next BOOK & 'prev' to store address of previous BOOK
        int ID;         //variable to store ID of a book
        string bookName;//string to store name of a book
        string author;  //string to store name of author of book
        string book_type;//string to store type of a book
        long copies;    //variable to store no. of copies a book
        long price;     //variable to store price of a book
        string status;  //to store status of a book, either its in stock or not
        dynamicQueue<string> book_queue; //created an object of queueClass as data member of each Book


    BOOK()  //Constructor 0 argument to initialize everything
    {
        count++;    //increment counter
        ID=count;   //assign counter to ID to be ID of newly added book

        next = prev = 0;        //Initializing both pointers to 0

        bookName = "\0";
        author = "\0";
        book_type = "\0";
        copies = price = 0;
        status= "InStock";
    }

    BOOK(BOOK *n =  0, BOOK *p = 0, string book = "\0", string athr = "\0", string buk_type = "\0", long cp=0, long pr=0) //Constructor multiple arguments, to store information about a book
    {
        next = n;       //store contents of user-given value n into next
        prev = p;       //store contents of user-given value p into previous

        bookName = book;//store contents of user-given value book into bookName
        author = athr;  //store contents of user-given value athr into author
        book_type = buk_type;//store contents of user-given value buk_type into book_type
        copies = cp;    //store contents of user-given value cp into copies
        price = pr;     //store contents of user-given value pr into price
        if(copies>0)
            status= "InStock";
        else if (copies<1)
        {
            status= "OutOfStock";
        }
        count++;        //increment counter
        ID=count;       //assign counter to ID to be ID of newly added book
    }
};


    template <class mytype>     // definition of
    int BOOK<mytype>::count=0; // static variable to set ID for books

string book = "\0"

Huh? Why not just this: string book = ""; It's not necessary to specify '\0' because all string are null terminated. I don't think that is really a problem, just style. Nobody, like NOBODY, ever does that.

OK solved.
1. I used stringstream mystr (#include<sstream>)
2. I was trying to read bookstatus in load function which was WRONG.
3. correct while condition -> while(file>>ID>>bookName>>author>>book_type>>copies>>price)
4. Into while, correct reading ->> mystr>>ID>>bookName>>author>>book_type>>copies>>price;

LOVE YOU ALOT MY DeV Bros. YOU NAILED IT. THANKYOOOOOOOOOU!

This article has been dead for over six months. Start a new discussion instead.