【问题标题】:C++ data file not reading correctly when introducing ofstream?引入 ofstream 时 C++ 数据文件读取不正确?
【发布时间】:2023-08-13 06:28:01
【问题描述】:

好吧,这将是一个很长的...

项目应该做什么的解释:

我的最终项目是一个银行柜员系统,它将所有与帐户相关的数据存储在一个文本文件中。
有问题的文件 "accounts.txt" 是所有帐户数据的存储位置。它是可读写的,并且在引入 ofstream 时行为异常......

“accounts.txt”文件格式如下

01481
554-00-8336
简·琼斯
1483 N. RealmSecond Ave., 伯灵顿, VT 05401
564 425 5052
02650
727-22-1072
詹妮弗·阿姆斯特朗
1450 W. Main Rd., Burlington, VT 05401
202 545 5485

它继续重复相同的有序信息集...

程序的核心部分之一依赖于将这些值读入 5 个单独的数组,每个数组都与数据类型(姓名、地址等)有关。

我将转储整个程序,因为我认为可能有必要解决问题,只需了解有问题的主要函数是 addAccount() 并且位于底部。

请注意,此函数的目的是将整个 accounts.txt 文件逐行读取到内存中,确定用于存储文件的数组何时被空数据填充 (课程讲师告诉我们将数组大小设置为100,这意味着读取到数组中的大部分数据都是空的)从用户那里获取所需的帐户信息,更新内存中的文件,并重写文件...

还要注意文件格式是由课程讲师预先确定的

代码:

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>

using namespace std;

const int TELLERS_SIZE = 5;
const int ACCOUNTS_SIZE = 100;
const string TELLERS_FILE = "tellers.txt";
const string ACCOUNTS_FILE = "accounts.txt";

int beginMenu();
bool login(string fileName);
int baseMenu();
void searchAccount(string fileName);
void addAccount(string fileName);

int main() {

    int beginSelection;

        do {

            beginSelection = beginMenu();

            if (beginSelection == 2) {
                return 0;
            }

            bool loginIsTrue = login(TELLERS_FILE);

            while (loginIsTrue) {

                int baseSelection = baseMenu();

                if (baseSelection == 1) {
                    addAccount(ACCOUNTS_FILE);
                }

                if (baseSelection == 4) {
                    searchAccount(ACCOUNTS_FILE);
                }

                if (baseSelection == 8) {
                    loginIsTrue = false;
                }

            }

        } while (beginSelection == 1);

}

// Print the fisrt menu and return selection
int beginMenu() {
    // Establish return value and validation
    int menuSelection;
    string userInput;
    bool menuSelectionIsValid = false;

    // Print options
    do {
        cout << "\n";
        cout << "[1] Login" << "\n";
        cout << "[2] Quit" << "\n";
        cout << "Please enter a selection";
        cout << "\n";
        getline(cin, userInput);

        // Validate input
        if (userInput == "1") {
            menuSelectionIsValid = true;
            menuSelection = 1;
        }

        else if (userInput == "2") {
            menuSelectionIsValid = true;
            menuSelection = 2;
        }

        else {
            cout << "Invalid input!" << "\n";
        }

    } while (!menuSelectionIsValid);

    return menuSelection;
}

// Perform login and return true or false
bool login(string fileName) {

    // Establish variables
    string username[TELLERS_SIZE];
    string password[TELLERS_SIZE];

    string usernameInput;
    string passwordInput;

    bool loginIsValid = false;

    // Establish fin
    ifstream fin(fileName);
    if (!fin.is_open()) {
        cout << "File cannot be opened " << fileName << "\n";
        return false;
    }

    // Read tellers.dat
    for (int i = 0; i < TELLERS_SIZE; i++) {
        fin >> username[i];
        fin >> password[i];
    }

        // Read user input
        cout << "\n";
        cout << "Username: ";
        getline(cin, usernameInput);
        cout << "Password: ";
        getline(cin, passwordInput);

        // Verify login information
        for (int i = 0; i < TELLERS_SIZE; i++) {
            if (username[i] == usernameInput && password[i] == passwordInput) {
                cout << "Login succesful" << "\n";
                loginIsValid = true;
                return true;
            }
        }

        // Inform user of error
        cout << "Invalid username or password!" << "\n";
        return false;
}

// Print base functions menu and return selection
int baseMenu () {

    // Establish return value and validation
    int menuSelection;
    string userInput;
    bool menuSelectionIsValid = false;

    do {

        // Print options
        cout << "\n";
        cout << "[1] Add Account" << "\n";
        cout << "[2] Remove Account" << "\n";
        cout << "[3] Update Account" << "\n";
        cout << "[4] Search Account" << "\n";
        cout << "[5] Make A Deposit" << "\n";
        cout << "[6] Make A Withdrawal" << "\n";
        cout << "[7] Check Balance" << "\n";
        cout << "[8] Logout" << "\n";
        cout << "Please enter a selection";
        cout << "\n";
        getline(cin, userInput);

        // Validate input
        if (userInput == "1") {
            menuSelectionIsValid = true;
            menuSelection = 1;
        }

        else if (userInput == "2") {
            menuSelectionIsValid = true;
            menuSelection = 2;
        }

        else if (userInput == "3") {
            menuSelectionIsValid = true;
            menuSelection = 3;
        }

        else if (userInput == "4") {
            menuSelectionIsValid = true;
            menuSelection = 4;
        }

        else if (userInput == "5") {
            menuSelectionIsValid = true;
            menuSelection = 5;
        }

        else if (userInput == "6") {
            menuSelectionIsValid = true;
            menuSelection = 6;
        }

        else if (userInput == "7") {
            menuSelectionIsValid = true;
            menuSelection = 7;
        }

        else if (userInput == "8") {
            menuSelectionIsValid = true;
            menuSelection = 8;
        }

        else {
            cout << "Invalid input!" << "\n";
        }

    } while (!menuSelectionIsValid);

    return menuSelection;
}

// Locate account and print relevant information
void searchAccount(string fileName) {

    // Establish arrays
    string accountNumber[ACCOUNTS_SIZE];
    string accountSSN[ACCOUNTS_SIZE];
    string accountName[ACCOUNTS_SIZE];
    string accountAddress[ACCOUNTS_SIZE];
    string accountPhone[ACCOUNTS_SIZE];

    // Establish validation variables
    string userInput;
    bool accountFound = false;

    // Establish and validate fin
    ifstream fin(fileName);
    if (!fin.is_open()) {
        cout << "File cannot be opened " << fileName << "\n";
    }

    // Get desired account number
    cout << "\n";
    cout << "Account number: ";
    getline(cin, userInput);

    // Read information from file
    for (int i = 0; i < ACCOUNTS_SIZE; i++) {
        getline(fin, accountNumber[i]);
        getline(fin, accountSSN[i]);
        getline(fin, accountName[i]);
        getline(fin, accountAddress[i]);
        getline(fin, accountPhone[i]);
    }

    // Search for account
    for (int i = 0; i < ACCOUNTS_SIZE; i++) {
        if (accountNumber[i] == userInput && userInput != "") {
            accountFound = true;
        }

        // Display account information
        if (accountFound == true) {
            cout << "Account Found" << "\n";
            cout << "Displaying account information" << "\n" << "\n";
            cout << accountNumber[i] << "\n";
            cout << accountSSN[i] << "\n";
            cout << accountName[i] << "\n";
            cout << accountAddress[i] << "\n";
            cout << accountPhone[i] << "\n";
            break;
        }
    }

    // Inform user that account doesnt exist
    if (accountFound == false) {
        cout << "Unable to find account: " << userInput << "\n";
    }
}

void addAccount(string fileName) {

    string accountNumber[ACCOUNTS_SIZE];
    string accountSSN[ACCOUNTS_SIZE];
    string accountName[ACCOUNTS_SIZE];
    string accountAddress[ACCOUNTS_SIZE];
    string accountPhone[ACCOUNTS_SIZE];

    ifstream fin(fileName);
    // ofstream fout(fileName);

    string userAccountNumber;
    string userAccountSSN;
    string userAccountName;
    string userAccountAddress;
    string userAccountPhone;

    bool accountNumberIsTaken = true;

    for (int i = 0; i < ACCOUNTS_SIZE; i++) {
        getline(fin, accountNumber[i]);
        getline(fin, accountSSN[i]);
        getline(fin, accountName[i]);
        getline(fin, accountAddress[i]);
        getline(fin, accountPhone[i]);
    }

    do {

        accountNumberIsTaken = false;

        cout << "\n";
        cout << "Enter desired account number: ";
        getline(cin, userAccountNumber);

        for (int i = 0; i < ACCOUNTS_SIZE; i++) {
            if (userAccountNumber == accountNumber[i] || userAccountNumber == "") {
                cout << "That account number is already in use" << "\n";
                accountNumberIsTaken = true;
                break;
            }
        }

    } while (accountNumberIsTaken);

    /*

    cout << "Enter SSN: ";
    getline(cin, userAccountSSN);
    cout << "Enter full name: ";
    getline(cin, userAccountName);
    cout << "Enter address: ";
    getline(cin, userAccountAddress);
    cout << "Enter phone number: ";
    getline(cin, userAccountPhone);

    for (int i = 0; i < ACCOUNTS_SIZE; i++) {
        if (accountNumber[i] == "") {
            cout << "empty space found at" << i;
            accountNumber[i] = userAccountNumber;
            accountSSN[i] = userAccountSSN;
            accountName[i] = userAccountName;
            accountAddress[i] = userAccountAddress;
            accountPhone[i] = userAccountPhone;
            break;
        }
    }

    for (int i = 0; i < ACCOUNTS_SIZE; i++) {
        fout << accountNumber[i] << "\n";
        fout << accountSSN[i] << "\n";
        fout << accountName[i] << "\n";
        fout << accountAddress[i] << "\n";
        fout << accountPhone[i] << "\n";
    }

    */
}

问题:

基本代码,没有任何注释,根本不起作用。

依赖读取 "accounts.txt"accountSearch()addAccount() 函数都会清楚地报告帐号“accounts.dat” 上的存在不存在。

注释掉 ofstream fout(fileName); 和依赖写入文件的 addAccount() 的下部AND"accounts.txt" 文件稍作更改并保存更改,一切又开始工作了

这个项目是用 Visual Studio 2019 编写的。

抱歉,如果这是一个糟糕的解释。如有必要,请要求澄清。

【问题讨论】:

  • 问题是什么
  • 您不能同时以ifstreamofstream 的形式打开filename
  • 读完文件后,关闭并重新打开进行写入。不要同时声明 ifs 和 ofs。

标签: c++ arrays fstream ifstream ofstream


【解决方案1】:

您不能同时将filename 作为ifstreamofstream 打开!因此,将fout 的声明/构造函数移动到读取fin 的代码之后,如下所示:

void addAccount(string fileName) {
    string accountNumber[ACCOUNTS_SIZE];
    string accountSSN[ACCOUNTS_SIZE];
    string accountName[ACCOUNTS_SIZE];
    string accountAddress[ACCOUNTS_SIZE];
    string accountPhone[ACCOUNTS_SIZE];

    ifstream fin(fileName);
    // ofstream fout(fileName); /// CANNOT BE HERE!

    string userAccountNumber;
    ///... Here, have all your reading and input code (as it is) …
    ///...

    ///... Finished reading, etc., so CLOSE "fin" then get the "fout" …
    fin.close();
    ofstream fout(fileName); // NOW we can create the output stream!
    ///... and use your existing code to do the writing

    for (int i = 0; i < ACCOUNTS_SIZE; i++) {
        fout << accountNumber[i] << "\n";
        fout << accountSSN[i] << "\n";
        fout << accountName[i] << "\n";
        fout << accountAddress[i] << "\n";
        fout << accountPhone[i] << "\n";
    }
    fout.close(); /// When finished, CLOSE the file!
}

【讨论】: