Search code examples
c++fstreamrecordbinaryfilesrandomaccessfile

fstream read and write functions errors


i am creating this program that stores some items into the (.dat) file.. the program seems to run smoothly but when i try to read the data from the file i see special character on my screen and none of the data that i was trying to save, was saved properly, note that when i run the similar code in main() it works and it actually shows me the correct output.. please help me on this i really don't know what to do here

void viewFile() {
    Product item;
    ifstream file("products.dat", ios::binary);
    if (!file.read(reinterpret_cast<char*>(&item), sizeof(Product))) {
        cout <<"failed to read";
        system("exit");
    }
    item.viewProduct();
    while (!file.eof()) {
        item.viewProduct();
        cout <<endl <<endl;
        file.read((char *)(&item), sizeof(Product));
    }
    file.close();
}
void addProductToInventory() {
    string name;
    int quantity;
    int pricePerItem;
    ofstream obj("products.dat", ios::out | ios::binary);

    Product item;
    int numberOfProducts;
    cout <<"enter the number of products you want to add in this inventory: ";
    cin >> numberOfProducts;

    for (int counter = 1; counter <= numberOfProducts; counter++) {
        Product product;        
        cout <<"enter the name of the object: ";
        cin >> name;
        cout <<"enter the quantity of the product: ";
        cin >> quantity;
        cout <<"enter the price of this product (per item): ";
        cin >> pricePerItem;

        product.setName(name);
        product.setQuantity(quantity);
        product.setPricePerItem(pricePerItem);

        if (!obj.write(reinterpret_cast<char*>(&product), sizeof(Product))) {
            cout <<"failed writing\n";
            system("exit");
        }
        cout <<"item added\n\n";
    }
    obj.flush();
    obj.close();
}

this is my code in main() which WORKS its exactly the same code.. i guess

ofstream file ("products.dat", ios::out | ios::binary | ios::trunc);
    Product p1("hammer", 12, 3);
    Product p2("screw driver", 43, 1);
    if (!file.write(reinterpret_cast<char*>(&p1), sizeof(Product))) {
        cout <<"failed to write";
        system("exit");
    }
    file.write(reinterpret_cast<char*>(&p2), sizeof(Product));
    file.close();
    ifstream file2("products.dat", ios::out | ios::binary);
    if (!file2.read(reinterpret_cast<char*>(&p1), sizeof(Product))) {
        cout <<"failed to read";
        system("exit");
    }
    while (!file2.eof()) {
        p1.viewProduct();
        cout <<endl <<endl;
        file2.read((char *)(&p1), sizeof(Product));
    }
    file2.close();
}

P.S i am really sorry if this comes out to be a messy question.. I have been debugging this for hours and now i can't even think straight.


Solution

  • Lets start by thinking about how pointers work.

    char* a = new char[2];
    a[0] = 'a';
    a[1] = 'b';
    char* b = a;
    std::cout << a[0] << a[1]; //prints ab
    std::cout << b[0] << b[1]; //prints ab
    a[1] = 'c';
    std::cout << b[0] << b[1]; //prints ac
    delete[] a;
    std::cout << b[0] << b[1]; //prints random garbage because the memory that b points at is deleted
    

    know lets start writing these pointers to files

    char* a = new char[2];
    a[0] = 'a';
    a[1] = 'b';
    ofstream outFile("products.dat", ios::binary | ios::trunc);
    outFile.write(reinterpret_cast<char*>(&a), sizeof(a));
    outFile.close();
    {
        ifstream inFile("products.dat", ios::binary);
        char* b;
        inFile.read(reinterpret_cast<char*>(&b), sizeof(b));
        std::cout << b[0] << b[1]; //prints ab
        a[1] = 'c';
        std::cout << b[0] << b[1]; //prints ac
    }
    delete[] a;
    {
        ifstream inFile("products.dat", ios::binary);
        char* b;
        inFile.read(reinterpret_cast<char*>(&b), sizeof(b));
        std::cout << b[0] << b[1];//prints random garbage because the memory that b points at is deleted
    }
    

    std::string contains pointers to dynamically allocated memory.

    You should do something like this.

    void viewFile() {
        ifstream file("products.dat", ios::binary);
        while (!file.eof()) {
            int nameLength = 0;
            if (!file.read(reinterpret_cast<char*>(&nameLength), sizeof(nameLength))) {
                cout <<"failed to read";
                system("exit");
            }
            std::string name{ nameLength, '?' };
            if (!file.read(name.data(), sizeof(char) * nameLength) {
                cout <<"failed to read";
                system("exit");
            }
            int quantity;
            if (!file.read(reinterpret_cast<char*>(&quantity), sizeof(quantity)) {
                cout <<"failed to read";
                system("exit");
            }
            int pricePerItem;
            if (!file.read(reinterpret_cast<char*>(&pricePerItem), sizeof(pricePerItem)) {
                cout <<"failed to read";
                system("exit");
            }
            Product item{ std::move(name),quantity, pricePerItem };
            item.viewProduct();
        }
        file.close();
    }
    void addProductToInventory() {
        string name;
        int quantity;
        int pricePerItem;
        ofstream obj("products.dat", ios::out | ios::binary);
    
        int numberOfProducts;
        cout <<"enter the number of products you want to add in this inventory: ";
        cin >> numberOfProducts;
    
        for (int counter = 1; counter <= numberOfProducts; counter++) {   
            cout <<"enter the name of the object: ";
            cin >> name;
            cout <<"enter the quantity of the product: ";
            cin >> quantity;
            cout <<"enter the price of this product (per item): ";
            cin >> pricePerItem;
    
            int nameLength = name.size();
            if (!obj.write(reinterpret_cast<char*>(&nameLength), sizeof(nameLength))) {
                cout <<"failed writing\n";
                system("exit");
            }
            if (!obj.write(name.data(), sizeof(char) * nameLength) {
                cout <<"failed writing\n";
                system("exit");
            }
            if (!obj.write(reinterpret_cast<char*>(&quantity), sizeof(quantity))) {
                cout <<"failed writing\n";
                system("exit");
            }
            if (!obj.write(reinterpret_cast<char*>(&pricePerItem), sizeof(pricePerItem))) {
                cout <<"failed writing\n";
                system("exit");
            }
            cout <<"item added\n\n";
        }
        obj.flush();
        obj.close();
    }