c++中的Fstream覆盖,即使使用ios::app

Fstream overwriting in C++ even with ios::app

本文关键字:ios app 中的 Fstream 覆盖 c++      更新时间:2023-10-16

我有一个问题。我启动了一个程序,可以保存数据(姓名、姓氏等),并将它们保存到一个txt文件中。问题是它覆盖了文件中的数据。我已经在fstream文件中写了ios::app,但没有任何区别。
你们能帮帮我吗?

我想给你代码,但它是西班牙语的,所以我想我帮不了你。

提前感谢;)

#include <iostream>
#include <windows.h>
#include <fstream>
#include <string.h>
using namespace std;
const int salario_minimo = 550;
fstream userdata;
int i;
struct FUNCIONARIO{
    char horario;
    char categria;
    int salario_inicial;
    string nombre;
    string apellido;
    int id;
    int salario_final;
};
FUNCIONARIO func[18];
int empleados;
int op;
int registrar(){
    userdata.open("FUNCIONARIOS.txt");
    cout << "Escriba el nombre del nuevo funcionario" << endl;
    cin >> func[empleados].nombre;
    cout <<"Escriba el apellido del nuevo funcionario"<<endl;
    cin >> func[empleados].apellido;
    cout<< "Especifique su puesto -Operario(O) o Gerente(G)"<<endl;
    cin >> func[empleados].categria;
    cout << "Especifique su horario -Manana(M), tarde(T) o noche(N)"<<endl;
    cin >> func[empleados].horario;
    i = empleados;
    empleados++;
    for(int o = 0; o < 18; o++){
        int p = o++;
        userdata << i << endl << empleados << endl << func[o].nombre << endl
                 << func[o].apellido << endl << func[o].categria << endl
                 << func[o].horario << endl << func[o].salario_inicial << endl
                 << func[o].salario_final << endl;
        userdata.close();
    }//RESOLVER OVERWRITING URGENTE!!!!!
    cout << "EMPLEADO NUMERO: " << empleados << endl;
    cout << "NOMBRE: " << func[i].nombre << endl;
    cout << "Apellido: " << func[i].apellido << endl;
    cout << "EMPLEO: ";
    switch (func[i].categria){
    case 'G': cout << "GERENTE" << endl; break;
    case 'O': cout << "OPERARIO" << endl; break;
    default: break;
    }
    cout << "HORARIO: ";
    switch(func[i].horario){
    case 'M':
        cout << "MANANA" << endl;
        break;
    case 'T':
        cout << "TARDE" << endl;
        break;
    case 'N':
        cout << "NOCHE" << endl;
        break;
    default:
        break;
    }
    cout << "SALARIO INICIAL: " <<func[i].salario_inicial << endl;
    cout << "SALARIO FINAL: " <<func[i].salario_final << endl;
    system("PAUSE");
    return 0;
}
int main(){
    ifstream comprobador;
    comprobador.open("FUNCIONARIOS.txt");
    if (comprobador.fail()){
        cout << "FILE NOT FOUND" << endl;
        userdata.open("FUNCIONARIOS.txt", fstream::in | fstream::out | ios_base::app);
        empleados = 0;
    }else{
        userdata.open("FUNCIONARIOS.txt",fstream::in | fstream::out | ios_base::app);
        userdata >> i >> empleados;
        userdata.close();
    }
    cout << "Numero Actual De Empleados:" << empleados << endl;
    cout << "Bienvenido a BUSINESS MANAGEMENT SOFTWARE 1.0n Por favor, seleccione una de estas opciones" << endl;
    cout << "1.Registrar Un Nuevo Funcionarion2.Ver Hojas De Pagon3.Salir" << endl;
    cin >> op;
    switch (op){
    case (1):
        registrar();
        break;
    /*case 2:
        mostrar();
        break;*/
    default:
        cerr << "Please, Choose A Valid Option" << endl;
        main();
        break;
    }
    userdata.close();
    return 0;
}

您的代码中可能存在各种错误。我会尽量强调其中最重要的几点。

局部变量优于全局变量

i, userdata, empleadosop不需要是全局的。这是c++,不是C,作用域非常重要。在这种情况下,不需要在fstream上调用close

不要递归地调用main

这不是错误的,也不是危险的,但这肯定是不好的做法。main方法应该从运行时调用,并且应该只调用一次。同样,这里也不需要递归,完全没有必要。只要写一个无限循环,并使用continuebreak/return跳出它。

的例子:

while (true) {
    int op = 0;
    cin >> op;
    switch (op) {
    case 1:
        registrar();
        return 0; // Note that break would only break switch, not the while-loop
    default:
        cerr << "Please, Choose A Valid Option" << endl;
        continue;
    }
}

在for循环中调用close

这个循环应该如何工作?它在第一次迭代后关闭userdata,然后再尝试向文件中写入17次(由于文件已关闭,因此将失败):

for(int o = 0; o < 18; o++){
    int p = o++;
    userdata << /* ... */ endl;
    userdata.close();
}//RESOLVER OVERWRITING URGENTE!!!!!

为什么文件被覆盖

可以在多个位置打开文件,但只有两种情况下指定app。看一下这部分代码,注意注释:

ifstream comprobador;
comprobador.open("FUNCIONARIOS.txt"); // Open the file for input, no app
if (comprobador.fail()){
    cout << "FILE NOT FOUND" << endl;
    // Ok, file not found, open with append (no need here, it's empty anyway!)
    userdata.open("FUNCIONARIOS.txt", fstream::in | fstream::out | ios_base::app);
    empleados = 0;
}else{
    // File already found and still open for input, reopen with new fstream
    // and specify append
    userdata.open("FUNCIONARIOS.txt",fstream::in | fstream::out | ios_base::app);
    // app places the filecursor at the end, the next statement will not work!
    userdata >> i >> empleados;
    // Now you close the file again!
    userdata.close();
}

所以基本上在第一种情况下,文件是空的并打开的,在第二种情况下,文件刚刚打开但随后关闭。这不是很好,if应该使userdata处于一致状态。现在假设文件是关闭的(else -statement),您调用registrarregistrar的第一行是这样的语句:

userdata.open("FUNCIONARIOS.txt");

再次打开文件,这次没有指定app

我建议打开文件一次在您的程序中使用ifstream作为输入,读取所有条目(如果有的话)到内存中,添加新条目,然后使用ofstreamios::trunc指定写入文件一次,重写所有条目到文件,或者使用ofstreamios::app指定打开文件,只添加一个条目。您必须首先解析整个文件,因为您需要最后一行的empleados的编号。如果在{ ... }范围内打开文件,它将在结束时关闭自己,不需要调用close。如果使用指定的文件名和标志直接构造fstream,也不需要调用open。一个例子:

void registrar() {
    // ...
    ofstream file("FUNCIONARIOS.txt", ios::app);
    if (file) {
        file << /* ... */ endl;
    }
} // file will be closed here because ofstreams destructor is called