C++,序列模式下二进制文件的问题

发布于 2024-11-13 00:47:19 字数 8275 浏览 3 评论 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
}

不要介意西班牙语文本,它只是用于用户通信。任何帮助将不胜感激

I have a quite difficult problem with binary files. I have been asked to make a program that stores information in files, but in Sequential mode. As I am not allowed to modify things in sequential mode directly, I made a function that first reads the file until I found the correct registry, while copying the other registries into an auxiliary file. when I finished modifying what I needed, I copy it to the auxiliary file and resume copying. When finished, I copy everything from the auxiliary file to the original one. I have made this following various examples of binary files, yet my program does some weird things. It begins eating all the information I wrote, leaving only the last entry (something like infinitely truncating), And even worse than that, there is a part (labeled the "pesky part") that starts an infinite loop that has no sense (it's as if the file had infinite size) I have chacked the logic like a thousand times and I don't seem to find any mistake, I don't know if you can help me, if I am missing something important.

Here are the classes I'm using

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;
    }
};

and the problematic function

 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
    }
}

In case you need it, this is the function to write a new entry, it works perfectly fine:

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
}

Don't mind the spanish text, it's just for user communication. Any help will be highly appreciated

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

生生漫 2024-11-20 00:47:19

对于初学者来说,您不会以二进制模式打开输入,所以除非
如果你在 Unix 下,你不会在磁盘上看到文件的字节映像。
如果我理解正确的话,您希望阅读您已经阅读过的文件
用相同的程序编写;如果是这样,则以不同的方式阅读和写作
模式将不起作用。

其次,您正在读取和写入复杂的数据结构(Cuenta
Cliente)使用 istream::readostream::write。这不
工作,除了极少数情况。无论是二进制还是文本,所有文件
有一个格式,并且在代码中必须遵守该格式。你的
类要么是 POD,要么足够接近 POD,但您可能不会
看到问题直到你在开发中做出一些改变
环境,但还是有的。 (事实上​​,你需要一个
reinterpret_cast 这样做应该是一个危险信号。)而且它肯定行不通
(Unix 下除外)如果您以文本模式读写。读取文件
在文本模式下这样写会返回额外的字符,或者停止
在 Windows 下,文件末尾之前。

另外,while ( file.eof() ) 不是读取文件的正确方法。这
file.eof() 的结果在输入之后才可靠
失败的。对于文本文件,您通常会使用:

while ( file >> something ) ...

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

阅读,

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

如果您解决了其余问题,应该可以工作。
这可能就是你无限循环的原因; istream 位于
由于文件结尾之外的某种原因导致错误状态,因此 eof()
永远不会成为现实。

For starters, you're not opening the input in binary mode, so unless
you're under Unix, you won't see the byte image of the file on disk.
If I understand correctly, you expect to read the files you've
written with the same program; if so, reading and writing in different
modes will not work.

Secondly, you're reading and writing complex data structures (Cuenta,
Cliente) using istream::read and ostream::write. This doesn't
work, except in a few rare cases. Whether binary or text, all files
have a format, and this format must be respected in the code. Your
classes are either PODs, or close enough to one, that you probably won't
see the problem until you make some changes in your development
environment, but it's still there. (The fact that you need a
reinterpret_cast to do so should be a red flag here.) And it definitely will not work
(except under Unix) if you read or write in text mode. Reading a file
written this way in text mode will return additional characters, or stop
before the end of the file, under Windows.

Also, while ( file.eof() ) is not a correct way to read a file. The
results of file.eof() are not reliable until after an input has
failed. For text files, you would normally use:

while ( file >> something ) ...

or

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

Reading as you do,

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

should work, provided you fix the rest of the problems.
This is probably the reason for your infinite loop; the istream is in
an error state for some reason other than end of file, so eof() will
never become true.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文