Archivo binario, al leerlo me muestra 2 veces el ultimo registro

Iniciado por .:BlackCoder:., 4 Marzo 2011, 04:27 AM

0 Miembros y 1 Visitante están viendo este tema.

.:BlackCoder:.

Buenas, estaba retomando el tema de archivos pero me quede estancado  :xD

Código (cpp) [Seleccionar]
#include <cstdlib>
#include <iostream>
#include <fstream>

using namespace std;

class Personas{
   private:
       char Nombre[30];
       int edad;
   public:
       Personas(char *x="",int e=0){
           strcpy(Nombre,x);
           edad=e;
       }
       const char* getNombre() const{
           return Nombre;
       }
       int getEdad() const{
           return edad;
       }
       void setNombre(const char cad[]){
           strcpy(Nombre,cad);
       }
       void setEdad(const int e){
           edad=e;
       }
};

void mostrar(){
   ifstream ent("PRUEBA.dat",ios::in | ios::binary);
   Personas aux;
   
   while(!ent.eof()){
       ent.read(reinterpret_cast<char *> (&aux),sizeof(Personas));
       cout<<aux.getNombre()<<endl<<aux.getEdad()<<endl;
   }
    ent.close();
}

int main(int argc, char *argv[])
{
   Personas persona("ALGUIEN",50);
   Personas persona2("Otro",20);
   
   ofstream sal("PRUEBA.dat", ios::out | ios::binary);
   
   sal.write(reinterpret_cast<char *>( &persona ), sizeof(Personas));
   sal.write(reinterpret_cast<char *>( &persona2 ), sizeof(Personas));
   sal.close();
   
   mostrar();
   
   system("PAUSE");
   return EXIT_SUCCESS;
}


El programa muestra 2 veces el ultimo registro es decir, muestra:

ALGUIEN
50
Otro
20
Otro
20


Por que?
"No te esfuerzes por saber mas, esfuerzate por ser el mejor en lo que sabes... Y asi sabras mas" .:BlackCoder:. jajaja




Littlehorse

Porque EOF devuelve true cuando ya pasaste por el final del archivo y no cuando estas a punto de pasarlo, por ende imprimes el contenido por duplicado.
Sigue paso por paso la ejecución del bucle en una hoja y chequea siempre cuales son los contenidos a imprimir, y quedara mas claro.

Por lo pronto puedes solucionarlo así:

Código (cpp) [Seleccionar]

while(!ent.eof() && ent.read(reinterpret_cast<char *> (&aux),sizeof(Personas)))
cout<<aux.getNombre()<<endl<<aux.getEdad()<<endl;


Saludos
An expert is a man who has made all the mistakes which can be made, in a very narrow field.

.:BlackCoder:.

Probe y si funciona pero no comprendo bien que sucede... read() devuelve un flujo, cierto? Cuando haces:
Código (cpp) [Seleccionar]
while(!ent.eof() && ent.read(reinterpret_cast<char *> (&aux),sizeof(Personas)))

aca la segunda condicion se cumple siempre y cuando no "lea" el eof...?

Crei que era lo mismo que:

Código (cpp) [Seleccionar]
while(ent.good())

Pero nop... Es que acaso el flujo "ent" no se coloca en mal estado cuando lee el EOF?...
"No te esfuerzes por saber mas, esfuerzate por ser el mejor en lo que sabes... Y asi sabras mas" .:BlackCoder:. jajaja




Littlehorse

Claro, por eso dije "por lo pronto"; para que puedas ver la lógica del error.
En la ultima lectura se establece failbit y ent.read devuelve NULL en lugar de *this, ergo la condición ya no se cumple y por eso los datos no se repiten.

Saludos
An expert is a man who has made all the mistakes which can be made, in a very narrow field.

.:BlackCoder:.

Cita de: Littlehorse en 12 Marzo 2011, 21:55 PM
ent.read devuelve NULL en lugar de *this

Gracias  :D, no sabia esa parte, crei que devolvia *this, y si ponia el failbit en mal estado...

Cita de: Littlehorse en 12 Marzo 2011, 21:55 PM
En la ultima lectura se establece failbit

Pero si en la ultima se establece failbit porque esto no funciona?

Código (cpp) [Seleccionar]
while(!ent.fail()){
        ent.read(reinterpret_cast<char *> (&aux),sizeof(Personas));
        cout<<aux.getNombre()<<endl<<aux.getEdad()<<endl;
    }


Yo creo que ciertamente devuelve null en vez de *this por el error... pero no establece por si sola el failbit en mal estado...

Hice esto para usar la condicion con good(), no muestre el de nuevo el ultimo registro... Y no poner la lectura en la condicion del while (se ve raro xD)
Código (cpp) [Seleccionar]
    while(ent.good()){
        if (ent.read(reinterpret_cast<char *> (&aux),sizeof(Personas)))
            cout<<aux.getNombre()<<endl<<aux.getEdad()<<endl;
        }



Saludos...
"No te esfuerzes por saber mas, esfuerzate por ser el mejor en lo que sabes... Y asi sabras mas" .:BlackCoder:. jajaja




Littlehorse

Código (cpp) [Seleccionar]

while(!ent.fail()){
        ent.read(reinterpret_cast<char *> (&aux),sizeof(Personas));
        cout<<aux.getNombre()<<endl<<aux.getEdad()<<endl;
    }


Esto no funciona como esperas porque cometes el mismo error que en el código anterior. Cuando ent.read devuelve NULL y se establece failbit, vos todavía estas dentro del bloque de ejecución del ciclo, por lo tanto imprimís una vez mas el contenido que leíste en la pasada anterior.

En cuanto a lo de failbit, no lo he probado, pero estoy seguro, de hecho si así no fuese el código anterior seria un ciclo infinito. Prueba revisando los valores de retorno (para eso están ;D ) y quedara mas claro!

Código (cpp) [Seleccionar]
while(!ent.fail()){
        cout<<"Read return value: "<<ent.read(reinterpret_cast<char *> (&aux),sizeof(Personas))<<endl;
        cout<<aux.getNombre()<<endl<<aux.getEdad()<<endl;
    }


Saludos
An expert is a man who has made all the mistakes which can be made, in a very narrow field.

.:BlackCoder:.

Ah ya me puse a probar un poco de cosas y vi que el failbit se coloca en true es despues de leer el EOF mas no al momento de leerlo...

Gracias por la ayuda me habia quedado trancado con esa duda  :xD

Saludos...
"No te esfuerzes por saber mas, esfuerzate por ser el mejor en lo que sabes... Y asi sabras mas" .:BlackCoder:. jajaja