删除文件中的内容

时间:2014-11-30 08:51:07

标签: c++

我正在创建一个程序,允许用户创建银行帐户并将其保存为文件,您也可以删除它们。我的代码删除文件中的帐户时遇到问题,我删除帐户的功能如下所示。

int deleteCustomer(account acc[], int numCust)
{
    string target;
    bool accFound = false;
    int count = 0;

    cout << "Enter account number: ";
    cin >> target;

    for (int i = 0; i < numCust; i++)
    {
        if (acc[i].acctNum == target)
        {
            accFound = true;
            break;
        }
        count++;
    }

    if (accFound == false)
    {
        cout << "That account does not exist." << endl;
        system("pause");
        system("cls");
    }
    else if (accFound == true)
    {
        ofstream outFile;
        outFile.open("customer.dat");

        for (int i = count; i < numCust - 1; i++)
        {
            outFile << acc[i+1].acctNum;
            outFile << '#';
            outFile << acc[i+1].name;
            outFile << '#';
            outFile << acc[i+1].cBal;
            outFile << '#';
            outFile << acc[i+1].sBal;
            outFile << '#';
        }
        numCust--;
        outFile.close();
    }

    return numCust;
}

该功能应该覆盖用户选择的帐户,方法是将文件保存在前一个位置并返回新的客户数。它似乎运行良好,但它没有做任何事情,我不确定为什么。任何输入都会有所帮助,谢谢。

3 个答案:

答案 0 :(得分:2)

这里有几个问题:

  • 您的帐户查找应该有效,但是您稍微过度复杂(您只需要一个值而不是三个,但现在让我们跳过它)。如果您有兴趣,请告诉我。
  • 您实际上从未删除过任何帐户(只是减少了总帐户数;这会导致最后一个帐户被删除)。
  • 将帐户保存到文件时,从所选索引开始,根本没有任何意义。
    • 假设您有10个帐户,索引0到9。
    • 用户从索引5处选择帐户。
    • 只保存帐户索引6到9(!)。
    • 用户从索引0处选择帐户。
    • 您只保存索引1到9。

一些风格的东西:

  • 您基本上将所选帐户的索引存储在count中。这很好,但非常误导。不要使用误导性的变量名。正如您从上面的评论中可以看出的那样,我也误读了那一部分。
  • 您可以只编写if (booleanValue == true)而不是编写if (booleanValue),这会产生相同的代码,但会更短,读取速度可能更快。以类似的方式,您可以将if (booleanValue == false)替换为!booleanValue
  • 如果可以,请不要省略std等名称空间(例如,使用std::string而不是string并避免using namespace std;),以避免编写具有暧昧代码的内容。如果您使用的其他名称空间也包含string(或任何其他成员),那么您无论如何都必须明确命名名称空间,或者至少让其他人在阅读您的代码时感到困惑。还有无意中使用不同类型引入的潜在错误。

解决实际问题:

我认为这是一些家庭作业或一些教程/类代码或类似的东西?如果是这样,请不要复制以下代码,而是尝试考虑它是如何工作的。一旦理解了,就自己实施,只有在你真正陷入困境时才使用我的代码片段。

一般来说,保持代码和功能最小化是一种很好的软件设计。不要创造超级功能&#34;做几件事。同时尝试使代码可重用,因此如果您更改了某些内容,您只能在一个地方进行调整。

以上面的代码为例。无论何时添加,删除或更新帐户,您都必须编写新文件。您是否计划多次复制相同的代码?如果您不得不调整文件格式,则必须随处更改。

您还需要一些方法来实际删除客户数据集。您可能知道,删除数组中的条目将要求您移动它后面的所有条目(以保持它的连续性)。这可能是一项非常昂贵的操作。

为避免这种情况,我要将新成员bool valid添加到account。默认情况下,此项设置为false。一旦有一些数据(通过从文件或用户读取),它的值将被设置为true

因此,将其拆分为两个独立的函数(将公共代码 - 保存 - 移动到自己的函数中):

// By returning an integer value, you're able to communicate issues or problems
// without having to rely on exceptions (in case you're using C++).
// Note that I don't do any error checking here for simplicity.

// Parameters:
// filename - the target file to write
// acc - the array holding all customer accounts
// size - the maximum amount of values in acc

// Return value: 0, if everything went fine
// (I skipped actual error handling to keep it simple!)
int saveCustomers(const char *filename, account acc[], int size) {
    std::ofstream outFile(filename);

    // Iterate over all entries
    for (int i = 0; i < num; ++i) {
        // Do we actually have to store the account?
        if (acc[i].valid) {
            outfile << acc[i].acctNum << '#' << acc[i].name; // write all the values the way you did
        }
    }
    outFile.close();
    return 0; // Everything ok
}

既然已经完成,您就可以创建功能来修改客户数据了:

int deleteCustomerByNumber(account acc[], int num, std::string target) {
    // Iterate over all accounts and look for the selected one
    for (int i = 0; i < num; ++i) {
        // Only check valid accounts and see whether it's the target
        if (acc[i].valid && acc[i].acctNum == target) {
            acc[i].valid = false; // Mark it as invalid
            return 0; // Everything ok
        }
    }
    return 1; // Didn't find it!
}

以类似的方式,您可以查找空/未使用的条目以实际向其写入数据。


奖金 - 替代(STL)方法:

由于您使用的是C ++,我建议您使用不同的数据结构,而不仅仅是一个简单的数组:

如果您使用STL容器(更具体地说:地图),您可以更轻松地处理所有事情。

#include <map>

// Create a typedef to simplify expressions
typedef std::map<std::string, account> accmap;

// All accounts would be stored in this object:
accmap accounts;

// To do a quick lookup of any account:
accmap::const_iterator a = accounts.find(accountNumber);

if (a == accounts.end())
    ;// Account not found!
else {
    a->first; // This is your account number
    a->second; // This is your `account` object
}

// To delete a specific account:
accounts.erase(accountNumber)

// To create a new account simply access it:
accounts[accountNumber].name = newName;

答案 1 :(得分:1)

您需要保存所有之前索引和之后索引,否则您实际上只删除了一个以上的帐户。大概你也应该从输入数组中删除记录。您也没有对输入或输出进行任何错误处理。你需要修复你的输出循环,它没有正确使用索引。

试试这个:

int deleteCustomer(account acc[], int numCust)
{
    string target;
    int accFound = -1;

    cout << "Enter account number: ";
    if (cin >> target)
    {    
        for (int i = 0; i < numCust; ++i)
        {
            if (acc[i].acctNum == target)
            {
                accFound = i;
                break;
            }
        }
    }

    if (accFound == -1)
    {
        cout << "That account does not exist." << endl;
        system("pause");
        system("cls");
    }
    else
    {
        for (int i = accFound+1; i < numCust; ++i)
            acc[i-1] = acc[i];
        --numCust;

        ofstream outFile;
        outFile.open("customer.dat");

        for (int i = 0; (i < numCust) && (outFile); ++i)
        {
            outFile << acc[i].acctNum;
            outFile << '#';
            outFile << acc[i].name;
            outFile << '#';
            outFile << acc[i].cBal;
            outFile << '#';
            outFile << acc[i].sBal;
            outFile << '#';
        }

        if (!outFile)
            cout << "Error saving customer file" << endl;
    }

    return numCust;
}

如果您不想更新阵列,那么您可以改为:

int deleteCustomer(account acc[], int numCust)
{
    string target;
    int accFound = -1;

    cout << "Enter account number: ";
    if (cin >> target)
    {    
        for (int i = 0; i < numCust; ++i)
        {
            if (acc[i].acctNum == target)
            {
                accFound = i;
                break;
            }
        }
    }

    if (accFound == -1)
    {
        cout << "That account does not exist." << endl;
        system("pause");
        system("cls");
    }
    else
    {
        ofstream outFile;
        outFile.open("customer.dat");

        for (int i = 0; (i < numCust) && (outFile); ++i)
        {
            if (i != accFound)
            {
                outFile << acc[i].acctNum;
                outFile << '#';
                outFile << acc[i].name;
                outFile << '#';
                outFile << acc[i].cBal;
                outFile << '#';
                outFile << acc[i].sBal;
                outFile << '#';
            } 
        }

        if (!outFile)
            Cout << "Error saving customer file" << endl;

        --numCust;
    }

    return numCust;
}

最后,在更新文件时,最好先将新数据写入临时文件,然后仅在一切成功时将原始文件替换为临时文件。这样可以降低破坏原始文件的风险。

答案 2 :(得分:0)

要删除文件&#34;上的帐户,这部分代码:

    for (int i = count; i < numCust - 1; i++)
    {
        outFile << acc[i+1].acctNum;
        outFile << '#';
        outFile << acc[i+1].name;
        outFile << '#';
        outFile << acc[i+1].cBal;
        outFile << '#';
        outFile << acc[i+1].sBal;
        outFile << '#';
    }

应该是

    for (int i = 0; i < numCust; i++)
    {
        if(i == count) continue;// remove the account user selected
        outFile << acc[i].acctNum;
        outFile << '#';
        outFile << acc[i].name;
        outFile << '#';
        outFile << acc[i].cBal;
        outFile << '#';
        outFile << acc[i].sBal;
        outFile << '#';
    }