C ++, Проблемы с двоичными файлами в режиме последовательности - PullRequest
0 голосов
/ 02 июня 2011

У меня довольно сложная проблема с бинарными файлами.Меня попросили сделать программу, которая хранит информацию в файлах, но в последовательном режиме.Поскольку мне не разрешено изменять вещи в последовательном режиме напрямую, я создал функцию, которая сначала читает файл, пока не найдет правильный реестр, при копировании других реестров во вспомогательный файл.Когда я закончу изменять то, что мне нужно, я копирую его во вспомогательный файл и возобновляю копирование.Когда я закончу, я копирую все из вспомогательного файла в исходный.Я сделал это на следующих примерах бинарных файлов, но моя программа делает некоторые странные вещи.Он начинает пожирать всю информацию, которую я написал, оставляя только последнюю запись (что-то вроде бесконечно усеченного), и, что еще хуже, есть часть (помеченная как «надоедливая часть»), которая запускает бесконечный цикл, который не имеет смысла (этокак будто файл имеет бесконечный размер) Я сотворил логику тысячу раз и, похоже, не нахожу ошибки, не знаю, сможете ли вы мне помочь, если я упустил что-то важное.

Вот классы, которые я использую

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
}

Не обращайте внимания на испанский текст, это просто для общения с пользователем.Любая помощь будет высоко оценена

1 Ответ

2 голосов
/ 02 июня 2011

Для начала, вы не открываете вход в двоичном режиме, так что если вы находитесь под Unix, вы не увидите байтовое изображение файла на диске. Если я правильно понимаю, вы ожидаете прочитать файлы, которые вы написанный с той же программой; если это так, чтение и запись в разных режимы работать не будут.

Во-вторых, вы читаете и пишете сложные структуры данных (Cuenta, Cliente) с использованием istream::read и ostream::write. Это не работа, за исключением нескольких редких случаев. Бинарные или текстовые, все файлы иметь формат, и этот формат должен соблюдаться в коде. Ваш классы либо POD, либо достаточно близки к одному, что вы, вероятно, не будете увидеть проблему, пока вы не внесете некоторые изменения в разработку среда, но она все еще там. (Тот факт, что вам нужно reinterpret_cast для этого должен быть красный флаг.) И он определенно не будет работать (кроме Unix), если вы читаете или пишете в текстовом режиме. Чтение файла написанный таким образом в текстовом режиме вернет дополнительные символы или остановит до конца файла, под Windows.

Кроме того, while ( file.eof() ) - это , а не правильный способ чтения файла. результаты file.eof() не являются надежными, пока после ввода не удалось. Для текстовых файлов вы обычно используете:

while ( file >> something ) ...

или

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

Чтение, как вы,

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

должно работать, если вы решите остальные проблемы. Это, вероятно, причина вашего бесконечного цикла; istream находится в состояние ошибки по какой-либо причине, отличной от конца файла, поэтому eof() будет никогда не станет правдой.

...