0

バイナリファイルに関して非常に難しい問題があります。情報をファイルに保存するプログラムを作成するように依頼されましたが、シーケンシャルモードです。シーケンシャルモードで直接変更することは許可されていないため、他のレジストリを補助ファイルにコピーしながら、正しいレジストリが見つかるまで最初にファイルを読み取る関数を作成しました。必要なものを変更し終えたら、それを補助ファイルにコピーして、コピーを再開します。終了したら、補助ファイルから元のファイルにすべてをコピーします。私はバイナリファイルのさまざまな例に従ってこれを作成しましたが、私のプログラムはいくつかの奇妙なことをします。それは私が書いたすべての情報を食べ始め、最後のエントリ(無限に切り捨てるようなもの)だけを残します、そしてそれよりもさらに悪いことに、一部(「厄介な部分」とラベル付けされています)があります

これが私が使っているクラスです

class Cliente{
public:
    int numCuenta;
    char dni[10];
    char nombre[40];
};

class Cuenta{
private:        
    int numCuenta;
    double monto;
    int numDuenhos;

public:
    const static double MONTO_MIN = 100.0;
    Cuenta(){
        numCuenta = 0;
        monto = 0;
        numDuenhos = 0;
    }
    int getnumCuenta(){
        return numCuenta;
    }
    void setnumCuenta(int numCuenta){
        this->numCuenta= numCuenta;
    }
    int getnumDuenhos(){
        return numDuenhos;
    }
    void setnumDuenhos(int numDuenhos){
        this->numDuenhos= numDuenhos;
    }
    double getMonto(){
        return monto;
    }
    void setMonto(double monto){
        this->monto = monto;
    }
};

と問題のある機能

 void modificarCuenta() {
    Cuenta aux;
    Cliente c;
    ifstream rep_cuentas("cuentas.bin");
    ofstream buf_cuentas("cuentas_rep.bin",ios::out | ios::trunc | ios::binary);
    if(!rep_cuentas) {
        cout <<endl << "Error al leer fila principal";
    }
    else if(!buf_cuentas) {
        cout << endl << "Error al abrir el archivo buffer";
    }
    else {
        cout <<endl << "Ingrese el numero de cuenta a modificar: "; //id of entry
        int num_cuenta;
        cin >> num_cuenta;
        ifstream rep_clientes("clientes.bin");
        ofstream buf_clientes("cilentes_rep.bin",ios::out | ios::trunc | ios::binary);
        //este archivo es necesario, por eso termina si no lo lee
        if (!rep_clientes) {
            cerr << "Error al Abrir el Archivo de Clientes" << endl;
            return;
        }
        rep_cuentas.read(reinterpret_cast<char *>(&aux),sizeof(Cuenta));
        while(!rep_cuentas.eof()){
            if(aux.getnumCuenta() == num_cuenta){
                rep_clientes.read(reinterpret_cast<char *>(&c),sizeof(Cliente));
                while(!rep_clientes.eof()){
                    if(c.numCuenta == num_cuenta){
                        cout << "DNI del Cliente: " << c.dni << endl; //old dni
                        cout << "Nombre del Cliente: " << c.nombre << endl; // old name
                        cout << "Modificar estos datos? (1 para confirmar): ";
                        int opc;
                        cin >> opc;
                        if (opc == 1){
                            c.numCuenta = aux.getnumCuenta();
                            cout << endl << "Ingrese nuevo DNI: "; //new dni
                            cin >> c.dni;
                            cout << endl << "Ingrese nuevo Nombre: "; //new name
                            cin >> c.nombre;
                        }
                    }
                    buf_clientes.write(reinterpret_cast<char *>(&c),sizeof(Cliente));
                    rep_clientes.read(reinterpret_cast<char *>(&c),sizeof(Cliente));
                }
                int num = aux.getnumDuenhos();
                while(true){
                    cout << endl << "Desea ingresar mas duenhos? (1 para confirmar): "; //appending new user?
                    int op;
                    cin >> op;
                    if (op == 1){
                        c.numCuenta = aux.getnumCuenta();
                        cout << endl << "Ingrese nuevo DNI: "; //new dni
                        cin >> c.dni;
                        cout << endl << "Ingrese nuevo Nombre: "; //new name
                        cin >> c.nombre;
                        num++;
                        buf_clientes.write(reinterpret_cast<char *>(&c),sizeof(Cliente));                                            
                    }
                    else{ 
                        aux.setnumDuenhos(num);
                        break;
                    }
                }
            }
            buf_cuentas.write(reinterpret_cast<char *>(&aux),sizeof(Cuenta));
            rep_cuentas.read(reinterpret_cast<char *>(&aux),sizeof(Cuenta));
        }
        rep_clientes.close();
        buf_clientes.close();
    }

    rep_cuentas.close();
    buf_cuentas.close();
    ofstream rcuentas("cuentas.bin",ios::out | ios::trunc| ios::binary);
    ifstream bcuentas("cuentas_rep.bin");
    if(!rcuentas) {
        cout << endl << "Error al abrir la fila principal";
    }
    else if(!bcuentas) {
        cout << endl << "Error al abrir el archivo buffer";
    }
    else{
        bcuentas.read(reinterpret_cast<char *>(&aux),sizeof(Cuenta));
        while(!bcuentas.eof()){
            rcuentas.write(reinterpret_cast<char *>(&aux),sizeof(Cuenta));
            bcuentas.read(reinterpret_cast<char *>(&aux),sizeof(Cuenta));
        }
        rcuentas.close();
        bcuentas.close();
        ofstream rclientes("clientes.bin",ios::out | ios::trunc | ios::binary);
        ifstream bclientes("clientes_rep.bin");
        bclientes.read(reinterpret_cast<char *>(&c),sizeof(Cliente));
        //pesky part
        while(!bclientes.eof()){
            rclientes.write(reinterpret_cast<char *>(&c),sizeof(Cliente));
            bclientes.read(reinterpret_cast<char *>(&c),sizeof(Cliente));                                
        }                            
        //end of pesky part
        bclientes.close();
        rclientes.close();
        cout << endl << "Modificacion Realizada con Exito" << endl;  //confirmation text
    }
}

必要な場合、これは新しいエントリを書き込む関数であり、完全に正常に機能します。

void crearCuenta(){
    Cuenta aux;
    aux.setnumCuenta(0);
    ifstream rcuentas("cuentas.bin");
    if(!rcuentas){
        cout<< endl <<"Primer uso del Sistema detectado, generando numero de cuenta inicial" <<endl;
    }
    else {
        rcuentas.read(reinterpret_cast<char *>(&aux),sizeof(Cuenta));
        while(!rcuentas.eof()){
            rcuentas.read(reinterpret_cast<char *>(&aux),sizeof(Cuenta));
        }
        rcuentas.close();
    }
    Cuenta cu;         
    cu.setnumCuenta(aux.getnumCuenta() + 1);
    int num_duenhos = 0;
    ofstream a_clientes("clientes.bin",ios::app |ios::binary);
    while(true){
        char dni[10];
        cout << "Ingrese el DNI del Duenho: "; //new dni
        Cliente c;
        cin >> c.dni;
        cout << "Ingrese el Nombre del Duenho: "; //new name
        cin >> c.nombre;
        c.numCuenta = cu.getnumCuenta();
        num_duenhos++;
        a_clientes.write(reinterpret_cast<char *>(&c),sizeof(Cliente));
        cout << "Desea ingresar otro duenho? (escriba 1 para confirmar): "; //another entry?
        int val;
        cin >> val;
        if (val != 1)
            break;
    }
    cu.setnumDuenhos(num_duenhos);
    while(true){
        double monto;
        cout << endl;
        cout << "Ingrese el monto con el cual iniciara la cuenta:"; //numerical value (greater than 100)
        cin >> monto;
        if (monto < Cuenta:: MONTO_MIN){
            cout << "Debe ingresar un valor mayor a " << Cuenta::MONTO_MIN << endl;
        }
        else{
            cu.setMonto(monto - monto * 0.005);
            break;
        }
    }
    ofstream acuentas("cuentas.bin",ios::app| ios::binary);
    if(!acuentas){
        cout<< endl <<"ERROR en la fila secuencial" <<endl;
    }
    else{
        acuentas.write(reinterpret_cast<char *>(&cu),sizeof(Cuenta));
        acuentas.close();
    }
    cout << "Cuenta Guardada Satisfactoriamente con número: " << cu.getnumCuenta() << endl;  //confirmation text
}

スペイン語のテキストは気にしないでください。ユーザーとのコミュニケーションのためだけのものです。どんな助けでも大歓迎です

4

1 に答える 1

2

手始めに、バイナリモードで入力を開いていないため、Unixを使用していない限り、ディスク上のファイルのバイトイメージは表示されません。私が正しく理解していれば、同じプログラムで書いたファイルを読むことを期待しています。その場合、異なるモードでの読み取りと書き込みは機能しません。

次に、とを使用して複雑なデータ構造( CuentaCliente)を読み書きしています。いくつかのまれなケースを除いて、これは機能しません。バイナリであろうとテキストであろうと、すべてのファイルにはフォーマットがあり、コードではこのフォーマットを尊重する必要があります。クラスはPODであるか、PODに十分近いため、開発環境に変更を加えるまで問題は発生しない可能性がありますが、それでも問題は解決しません。(そうする必要があるという事実は、 ここでは危険信号であるはずです。)そして、テキストモードで読み書きする場合、それは間違いなく機能しません(Unixの場合を除く)。この方法で記述されたファイルをテキストモードで読み取ると、Windowsで追加の文字が返されるか、ファイルの終わりの前で停止します。istream::readostream::writereinterpret_cast

また、ファイルを読み取る正しい方法でwhile ( file.eof() )はありません。の結果はfile.eof()、入力が失敗するまで信頼できません。テキストファイルの場合、通常は次のものを使用します。

while ( file >> something ) ...

また

while ( std::getline( file, line ) ) ...

あなたがするように読んで、

while ( rep_clentes.read(...) ) ...

残りの問題を修正すれば、機能するはずです。これがおそらく無限ループの理由です。ファイルのistream終わり以外の理由でエラー状態になっているため、eof()trueになることはありません。

于 2011-06-02T17:27:36.440 に答える