-1

I have this school project of mine and I need some help to troubleshoot; I've debugged as far as if it goes into the while(prod_file.good()) loop and it does, it just fails to find an existing string within a file.

#include <iostream>
#include <fstream>
#include <stdio.h>
#include <string>
#include <conio.h>
#include <stdlib.h>
#include <string.h>

using namespace std;

#define PROD_SIZE 22

class PRODUCT {
public:

    string NAME;
    string QUANTITY;

} product;


int main() {
    int diff;
    string length;
    char answer = 0;
    string line;
    bool foundAndReplaced = false;

    cout << product.NAME.length() << endl;
    cout << product.NAME;

    fstream prod_file("data/available.dat", ios::out | ios::app);
    do {
        if(prod_file.is_open()) {

            cout << "Molq vavedete imeto na produkta: \n";
            getline(cin, product.NAME);


            if(product.NAME.length() < 30) {
                diff = 30 - product.NAME.length();

                for(int i = 1; i < diff; i++){
                    product.NAME.append(".");
                }
            }
            else if(product.NAME.length() > 30) {
                cout << "Product name cannot exceed 30 characters.";
                return 0;
            }

            //

            cout << "Molq vavedete kolichestvoto na produkta: \n";

            getline(cin, product.QUANTITY);



            size_t pos;

            while(prod_file.good()) {
                cout << "asd\n";
                getline(prod_file, line);
                pos = line.find(product.NAME);
                cout << "stignah\n";
                if(pos != string::npos) {
                    prod_file << product.NAME;
                    prod_file << "-" << product.QUANTITY << "\n";
                }
            }

        }

        else {
            cout << "Error: File inaccessible. (0x1)";
            return 0;
        }

        cout << "Do you want to add more products? Y/N \n\n";
        answer = 0;
        while (answer != 'y' && answer != 'Y' && answer != 'n' && answer != 'N') {
        answer = _getch();
        }
    }

    while(answer == 'Y' || answer == 'y');
    prod_file.close();

    cout << "Entries added." << "\n\n";

    return 0;
}

The idea of

size_t pos;

            while(prod_file.good()) {
                cout << "asd\n";
                getline(prod_file, line);
                pos = line.find(product.NAME);
                cout << "stignah\n";
                if(pos != string::npos) {
                    prod_file << product.NAME;
                    prod_file << "-" << product.QUANTITY << "\n";
                }
            }

Is to check for a certain string in a file and if it does not find the string to add to the file, if it finds it then it will not add it. Any idea why it fails the if?

  • 1
    Welcome to Stack Overflow. Please look at our [intro pages](https://stackoverflow.com/help), with special attention to the page on [minimal complete examples](https://stackoverflow.com/help/mcve). Simplify the code as much as you can -- while still reproducing the error -- and then give us the minimal code along with the file that it reads. – Beta Jun 20 '18 at 22:59
  • I need your help. My debugger is out of commission at the moment, so could you run the debugger and step through your code? Edit your post with the results of your debugging session. Thanks. – Thomas Matthews Jun 21 '18 at 00:29
  • See this [post about why `eof()` in a loop condition is wrong](https://stackoverflow.com/q/5605125/9254539). `good()` in a loop condition is wrong for the same reason. – BessieTheCookie Jun 21 '18 at 04:29

1 Answers1

1

You are opening prod_file for output only, not for input, so there is nothing for std::getline() to read from it.

You should NOT be trying to read from and write to the same file using a single stream. Open the original file for reading with one stream, and create a new file for writing with a separate stream. Use the first stream to scan the original file for existing entries, and use the second stream to write entries to the new file. When done, replace the original file with the new file if needed.

Try something like this:

#include <iostream>
#include <string>
#include <fstream>
#include <limits>
#include <cstdio>

using namespace std;

struct Product {
    string Name;
    int Quantity;
};

int main() {
    string line;
    char answer;
    bool found, added = false, copyLines = true;
    Product product;

    ifstream prod_file("data/available.dat");
    ofstream prod_file_new("data/available_new.dat", ios_base:::trunc);

    do {
        if (!prod_file || !prod_file_new) {
            cerr << "Error: File inaccessible." << endl;
            return 0;
        }

        do {
            cout << "Molq vavedete imeto na produkta: " << endl;
            if (!getline(cin, product.Name)) {
                if (!cin.eof()) {
                    cerr << "Error: user input failure." << endl;
                    return 0;
                }
                break;
            }

            if (product.Name.length() <= 30) {
                break;
            }

            cerr << "Product name cannot exceed 30 characters." << endl;
        }
        while (true);

        if (cin.eof()) {
            break;
        }

        if (product.Name.length() < 30) {
            product.Name.append(30 - product.Name.length(), '.');
        }

        //

        found = false;

        do {
            if (!getline(prod_file, line)) {
                if (!prod_file.eof()) {
                    cerr << "Error: input file failure." << endl;
                    return 0;
                }
                break;
            }

            if (copyLines) {
                if (!(prod_file_new << line << "\n")) {
                    cerr << "Error: output file failure." << endl;
                    return 0;
                }
            }

            found = (line.find(product.Name) != string::npos);
        }
        while (!found);

        if (!found) {
            cout << "Molq vavedete kolichestvoto na produkta: " << endl;

            if (!(cin >> product.Quantity)) {
                cerr << "Error: user input failure." << endl;
                return 0;
            }
            cin.ignore(numeric_limits<streamsize>::max(), '\n');

            if (!(prod_file_new << product.Name << "-" << product.Quantity << "\n")) {
                cerr << "Error: output file failure." << endl;
                return 0;
            }

            added = true;
        }

        cout << "Do you want to add another product? Y/N" << endl << endl;

        cin >> answer;
        while (answer != 'y' && answer != 'Y' && answer != 'n' && answer != 'N') {
            cin >> answer;
        }

        if (answer != 'Y' && answer != 'y')
            break;

        if (!prod_file.seekg(0)) {
            cerr << "Error: input file failure." << endl;
            return 0;
        }

        copyLines = false;
    }
    while (true);

    prod_file.close();
    prod_file_new.close();

    if (added) {
        if (remove("data/available.dat") == 0) {
            if (rename("data/available_new.dat", "data/available.dat") == 0) {
                cout << "Entries added." << endl << endl;
            }
            else {
                cerr << "Error: renaming available_new.dat to available.dat" << endl << endl;
            }
        }
        else {
            cerr << "Error: removing available.dat" << endl << endl;
        }
    }
    else {
        remove("data/available_new.dat");
        cout << "No Entries added." << endl << endl;
    }

    return 0;
}

Alternatively, read the existing file into memory, and then search and append to that as needed, and then write out a new file only if entries have been added, eg:

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
#include <algorithm>
#include <limits>
#include <cstdio>

using namespace std;

struct Product {
    string Name;
    int Quantity;
};

int main() {
    string line;
    char answer;
    bool found, added = false;
    Product product;
    vector<Product> products;

    ifstream prod_file("data/available.dat");
    if (!prod_file) {
        cerr << "Error: input file inaccessible." << endl;
        return 0;
    }

    while (getline(prod_file, line)) {
        istringstream iss(line);
        if (!(getline(iss, product.Name, '-') && (iss >> product.Quantity))) {
            cerr << "Error: input file malformed." << endl;
            return 0;
        }
        products.push_back(product);
    }

    if (!prod_file) {
        cerr << "Error: input file failure." << endl;
        return 0;
    }

    prod_file.close();

    do {
        do {
            cout << "Molq vavedete imeto na produkta: " << endl;
            if (!getline(cin, product.Name)) {
                if (!cin.eof()) {
                    cerr << "Error: user input failure." << endl;
                    return 0;
                }
                break;
            }

            if (product.Name.length() <= 30) {
                break;

            cerr << "Product name cannot exceed 30 characters." << endl;
        }
        while (true);

        if (cin.eof()) {
            break;
        }

        if (product.Name.length() < 30) {
            product.Name.append(30 - product.Name.length(), '.');
        }

        //

        found = std::find_if(products.begin(), products.end(),
            [&](const Product &p){ return (p.Name == product.Name); }
            ) != products.end();

        if (!found) {
            cout << "Molq vavedete kolichestvoto na produkta: " << endl;

            if (!(cin >> product.Quantity)) {
                cerr << "Error: user input failure." << endl;
                return 0;
            }
            cin.ignore(numeric_limits<streamsize>::max(), '\n');

            products.push_back(product);
            added = true;
        }

        cout << "Do you want to add another product? Y/N" << endl << endl;

        cin >> answer;
        while (answer != 'y' && answer != 'Y' && answer != 'n' && answer != 'N') {
            cin >> answer;
        }

        if (answer != 'Y' && answer != 'y')
            break;
    }
    while (true);

    if (added) {
        ofstream prod_file_new("data/available_new.dat", ios_base:::trunc);

        if (!prod_file_new) {
            cerr << "Error: output file inaccessible." << endl;
            return 0;
        }

        for (auto &p : products) {
            if (!(prod_file_new << p.Name << "-" << p.Quantity << "\n")) {
                cerr << "Error: output file failure." << endl;
                return 0;
            }
        }

        prod_file_new.close();

        if (remove("data/available.dat") == 0) {
            if (rename("data/available_new.dat", "data/available.dat") == 0) {
                cout << "Entries added." << endl << endl;
            }
            else {
                cerr << "Error: renaming available_new.dat to available.dat" << endl << endl;
            }
        }
        else {
            cerr << "Error: removing available.dat" << endl << endl;
        }
    }
    else {
        cout << "No Entries added." << endl << endl;
    }

    return 0;
}
Remy Lebeau
  • 454,445
  • 28
  • 366
  • 620