Foros del Web » Programación para mayores de 30 ;) » C/C++ »

[SOLUCIONADO] Guardar y leer objeto en archivo

Estas en el tema de Guardar y leer objeto en archivo en el foro de C/C++ en Foros del Web. Hola. Tengo un codigo que lee datos de un .txt, los procesa y los asigna a una clase. Lo que quisiera es guardar los objetos ...
  #1 (permalink)  
Antiguo 13/01/2016, 17:47
 
Fecha de Ingreso: enero-2016
Mensajes: 4
Antigüedad: 8 años, 3 meses
Puntos: 0
Guardar y leer objeto en archivo

Hola. Tengo un codigo que lee datos de un .txt, los procesa y los asigna a una clase. Lo que quisiera es guardar los objetos correspondientes a esa clase en un binario y recuperarlos la proxima vez que ejecute el programa.

En realidad solo necesito guardar los atributos "referido" y "clicks" que se ira acumulando con nuevos datos cada dia. El resto de los datos los puedo obtener del .txt. Entonces guardaria el atributo en otro.txt (aun estoy aprendiendo c++ y no termino de entender los archivos binarios) pero luego para recuperarlo tendria que reprocesarlo y convertirlo en un array o vector. No estoy seguro de que esta sea la opcion mas eficiente y por ello les solicito ayuda para guardar el objeto entero en un binario (de paso consigo practica con los binarios )
Desde ya muchas gracias por su ayuda


Código:
#include <iostream>
#include <fstream>
#include <string>
#include <stdlib.h> //para usar atoi que pasa de string a int // atof pasa de string a float
#include <sstream> // para usar ostringsteam que pasa de int a string

class referidosRegistro
{
    public:
        int numero;
        string bandera;
        string referido;
        string referidoDesde;
        string fechaExpiracion;
        string ultimoClick;
        int clicks;
        float media;
        int fechaExpiracionDias; //calculado

        //funcion que toma un getline declarado en creaClaseReferidoRegistro y lo transforma en un array. Tambien llama a la funcion declarador
        void stringToArray(string lineaReferido);
        //funcion que toma el array de la funcion anterior, convierte los tipos necesarios y los asigna como datos de la clase
        void declarador (string _numero, string _bandera, string _referido, string _referidoDesde, string _fechaExpiracion, string _ultimoClick, string _clicks, string _media);
};

//funcion que inicia la creacion de la clase
void creaClaseReferidoRegistro ()
{
    ifstream listaReferidos;
    listaReferidos.open("referidos.txt",ios::in);

    referidosRegistro referido[100];
    for (int i=0; i <=99; i++)
    {
        string lineaReferido;

        getline(listaReferidos, lineaReferido);

        referido[i].stringToArray(lineaReferido);
    };
};

//funcion que toma un getline de creaClaseReferidoRegistro y lo transforma en un array. Tambien llama a la funcion declarador
void referidosRegistro:: stringToArray(string lineaReferido)
{
    string _lineaReferido = lineaReferido;
    int lastPosicion = 0;
    int posicion = 0;
    string referidoArray[8];
    int i = 0;

    while (posicion != -1)
    {
        posicion = _lineaReferido.find(";",lastPosicion+1);

        if (i==0)
        {
            referidoArray[i] = _lineaReferido.substr(lastPosicion, posicion - lastPosicion);
        }
        else
        {
            referidoArray[i] = _lineaReferido.substr(lastPosicion+1, posicion - lastPosicion -1);
        }
        i++;
        lastPosicion = posicion;
    };

    declarador(referidoArray[0], referidoArray[1], referidoArray[2], referidoArray[3], referidoArray[4], referidoArray[5], referidoArray[6], referidoArray[7]);
};

//funcion que toma el array de la funcion anterior, convierte los tipos necesarios y los asigna como datos de la clase
void referidosRegistro:: declarador (string _numero, string _bandera, string _referido, string _referidoDesde, string _fechaExpiracion, string _ultimoClick, string _clicks, string _media)
{
    numero = atoi(_numero.c_str());
    bandera = _bandera;
    referido = _referido;
    referidoDesde = _referidoDesde;
    fechaExpiracion = _fechaExpiracion;
    ultimoClick = _ultimoClick;
    clicks = atoi(_clicks.c_str());
    media = atof(_media.c_str());
    fechaExpiracionDias = fechaADias(fechaExpiracion);
};



int main()
{
    creaClaseReferidoRegistro();
};

Última edición por coyoteazul; 13/01/2016 a las 18:06 Razón: olvido
  #2 (permalink)  
Antiguo 15/01/2016, 02:32
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 6 meses
Puntos: 204
Respuesta: Guardar y leer objeto en archivo

Si referidosRegistro no va a tener parte privada te aconsejo usar struct en vez de class. En C++ la única diferencia entre ambos es que la visibilidad por defecto es pública para struct y privada para class. Tu clase podría quedar entonces así:

Código C++:
Ver original
  1. struct referidosRegistro
  2. {
  3.   int numero;
  4.   string bandera;
  5.   string referido;
  6.   string referidoDesde;
  7.   string fechaExpiracion;
  8.   string ultimoClick;
  9.   int clicks;
  10.   float media;
  11.   int fechaExpiracionDias; //calculado
  12.  
  13.   //funcion que toma un getline declarado en creaClaseReferidoRegistro y lo transforma en un array. Tambien llama a la funcion declarador
  14.   void stringToArray(string lineaReferido);
  15.   //funcion que toma el array de la funcion anterior, convierte los tipos necesarios y los asigna como datos de la clase
  16.   void declarador (string _numero, string _bandera, string _referido, string _referidoDesde, string _fechaExpiracion, string _ultimoClick, string _clicks, string _media);
  17. };

Parece una tontería ahorrarse el "public" pero piensa que si la gente ve un struct por motivos históricos entenderá que sus variables internas son públicas... se mejora la legibilidad del código.

Por otro lado, las funciones no necesitan un ';' después de la llave de cierre. Esta característica es exclusiva de clases, estructuras y enumerados.

Y bueno, al lio. Quieres guardar el estado del objeto en un fichero. En C++ no tienes acceso directo a la memoria interna de los objetos (pongamos el string por ejemplo). Esto impide que puedas volcar el contenido de un objeto directamente al disco al estilo de C... si lo haces el fichero acabará almacenando punteros en vez de información útil. Es por este motivo que la única forma de guardar el estado del objeto es guardar cada elemento por separado.

Si vas a usar los streams de C++ puedes sobrecargar los operadores << y >> para almacenar y recuperar los datos del fichero.

Código C++:
Ver original
  1. ostream& referidosRegistro::operator<<(ostream& stream) const
  2. {
  3.   stream << numero << bandera << ...
  4.   return stream;
  5. }
  6.  
  7. istream& referidosRegistro::operator>>(istream& stream)
  8. {
  9.   stream >> numero >> bandera >> ...
  10.   return;
  11. }

Para algún tipo puede que tengas que modificar los flags del stream o hacer un volcado manual (por ejemplo si algún elemento almacena información binaria)... C++ es así y es complicado dar una norma general que se cumpla siempre :)
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #3 (permalink)  
Antiguo 15/01/2016, 21:24
 
Fecha de Ingreso: enero-2016
Mensajes: 4
Antigüedad: 8 años, 3 meses
Puntos: 0
Respuesta: Guardar y leer objeto en archivo

Gracias por tus consejos y ayuda. Por desgracia me da error "no match for 'operator<<' in 'historial' << ..." Seguramente lo estoy implementando mal ya que nunca había usado operator de esta forma, solo para el cout y sin declarar funciones especificas

Tuve que pasar la funcion que declaraba los objetos a main porque si no no me dejaba utilizarlos (imagino que los tomaria como variables locales y los borraria al finalizar esa funcion)

Código:
struct referidosRegistro
{
    int numero;
    string bandera;
    string referido;
    string referidoDesde;
    string fechaExpiracion;
    string ultimoClick;
    int clicks;
    float media;
    int fechaExpiracionDias; //calculado

    //funcion que toma un getline declarado en creaClaseReferidoRegistro y lo transforma en un array. Tambien llama a la funcion declarador
    void stringToArray(string lineaReferido);
    //funcion que toma el array de la funcion anterior, convierte los tipos necesarios y los asigna como datos de la clase
    void declarador (string _numero, string _bandera, string _referido, string _referidoDesde, string _fechaExpiracion, string _ultimoClick, string _clicks, string _media);

    ostream& operator<<(ostream& stream) const;
    istream& operator>>(istream& stream);
};

//funcion que inicia la creacion de la clase
void creaClaseReferidoRegistro ()
{
    //pasada a main

}

//funcion que toma un getline de creaClaseReferidoRegistro y lo transforma en un array. Tambien llama a la funcion declarador
void referidosRegistro:: stringToArray(string lineaReferido)
{
    string _lineaReferido = lineaReferido;
    int lastPosicion = 0;
    int posicion = 0;
    string referidoArray[8];
    int i = 0;

    while (posicion != -1)
    {
        posicion = _lineaReferido.find(";",lastPosicion+1);

        if (i==0)
        {
            referidoArray[i] = _lineaReferido.substr(lastPosicion, posicion - lastPosicion);
        }
        else
        {
            referidoArray[i] = _lineaReferido.substr(lastPosicion+1, posicion - lastPosicion -1);
        }
        i++;
        lastPosicion = posicion;
    };

    declarador(referidoArray[0], referidoArray[1], referidoArray[2], referidoArray[3], referidoArray[4], referidoArray[5], referidoArray[6], referidoArray[7]);
};

//funcion que toma el array de la funcion anterior, convierte los tipos necesarios y los asigna como datos de la clase
void referidosRegistro:: declarador (string _numero, string _bandera, string _referido, string _referidoDesde, string _fechaExpiracion, string _ultimoClick, string _clicks, string _media)
{
    numero = atoi(_numero.c_str());
    bandera = _bandera;
    referido = _referido;
    referidoDesde = _referidoDesde;
    fechaExpiracion = _fechaExpiracion;
    ultimoClick = _ultimoClick;
    clicks = atoi(_clicks.c_str());
    media = atof(_media.c_str());
    fechaExpiracionDias = fechaADias(fechaExpiracion);
};


//------------------------------------------------------------------------------------//-----------********
ostream& referidosRegistro::operator<<(ostream& stream) const
{
  stream << numero << bandera  << endl;
  return stream;
}

istream& referidosRegistro::operator>>(istream& stream)
{
  stream >> numero >> bandera;
  return stream; //tuve que declarar algo porque si no marcaba error
}
//------------------------------------------------------------------------------------//-----------********
int main()
{

    ifstream listaReferidos;
    listaReferidos.open("referidos.txt",ios::in);

    referidosRegistro referidoObj[100];
    for (int i=0; i <=99; i++)
    {
        string lineaReferido;

        getline(listaReferidos, lineaReferido);

        referidoObj[i].stringToArray(lineaReferido);
    };

    ifstream historial;
    historial.open("CoAz SaveFile",fstream::out);
    if (historial.good() == 1)
    {
        cout << "buen estado" << endl;

        for (int t=0;t<=5 ;t++)
        {
            historial << referidoObj[t];
        }
    }
    else
    {
        cout << "mal estado"<< endl;
        ofstream fs("CoAz SaveFile");

        for (int t=0;t<=5 ;t++)
        {
            historial << referidoObj[t];
        }
    }
};
  #4 (permalink)  
Antiguo 16/01/2016, 03:54
Avatar de xKuZz  
Fecha de Ingreso: febrero-2015
Ubicación: nullptr
Mensajes: 183
Antigüedad: 9 años, 2 meses
Puntos: 27
Respuesta: Guardar y leer objeto en archivo

El error procede de que como es normal no tienes hecho el operador '<<' para flujos de entrada (istream). Si no me equivoco lo que en realidad quieres hacer es declarar historial como ofstream.
  #5 (permalink)  
Antiguo 16/01/2016, 09:10
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 6 meses
Puntos: 204
Respuesta: Guardar y leer objeto en archivo

Si has usado cin y cout te habrás fijado en que:
  • Para enviar algo a cout se usa el operador <<
  • Para recibir algo de cin se usa el operador >>

Si has declarado << con ofstream y >> con ifstream... tienes que usar el operador << para almacenar datos en el stream y >> para recuperarlos... no usar << todo el rato.

Podrías usar << todo el rato si modificas la función

Código C++:
Ver original
  1. istream& referidosRegistro::operator>>(istream& stream)

y la dejas tal que:

Código C++:
Ver original
  1. istream& referidosRegistro::operator<<(istream& stream)

Ahora bien, esto te puede ocasionar dos problemas:
  1. Se dificulta la lectura del programa, ya que la gente espera que << funcione para guardar y >> para leer.
  2. Si usas un stream de lectura y escritura y llamas al operador <<... ¿Qué función se llama, la que lee del stream o la que escribe en el mismo? Tu no lo sabes, yo tampoco y el compilador tampoco, por lo que te dará un error de compilación.

Por cierto, estos operadores suelen devolver el objeto que han recibido como argumento para poder concatenar operadores:

Código C++:
Ver original
  1. std::cout << "A" << 5 << 'c';

Es equivalente a:

Código C++:
Ver original
  1. std::cout << "A";
  2. std::cout << 5;
  3. std::cout << 'c';

Para entender por qué funciona al concatenarlos tienes que ver los operadores como funciones de toda la vida pero con una sintaxis ligeramente diferente. Puesto a modo de función, que se puede, quedaría así:

Código C++:
Ver original
  1. std::cout.operator<<("A").operator<<(5).operator<<('c');

Y esto funciona porque....

std::cout.operator<<("A") imprime la cadena en la pantalla y retorna std::cout, luego lo siguiente que se ejecuta es...
std::cout.operator<<(5) que imprime el 5 en pantalla y se vuelve a retornar std::cout, con lo que la última parte de la línea acaba ejecutando...
std::cout.operator<<('c') que finalmente imprime el carácter por pantalla.

El compilador es tan listo (bueno, no es que sea listo, es que dice el estándar cómo tienen que funcionar estas cosas) que sabe cacharrear el código para convertir una sintaxis bonita, sencilla y legible en una amalgama de funciones... y todo sin que tú tengas que preocuparte de ello.

Espero que con estas aclaraciones te haya quedado el tema un poco más sencillo de digerir.

Un saludo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #6 (permalink)  
Antiguo 16/01/2016, 14:33
 
Fecha de Ingreso: enero-2016
Mensajes: 4
Antigüedad: 8 años, 3 meses
Puntos: 0
Respuesta: Guardar y leer objeto en archivo

Cita:
Iniciado por xKuZz Ver Mensaje
El error procede de que como es normal no tienes hecho el operador '<<' para flujos de entrada (istream). Si no me equivoco lo que en realidad quieres hacer es declarar historial como ofstream.
esos no son las lineas que estan justo antes de main?
Código:
ostream& referidosRegistro::operator<<(ostream& stream) const
{
  stream << numero << bandera  << endl;
  return stream;
}

istream& referidosRegistro::operator>>(istream& stream)
{
  stream >> numero >> bandera;
  return stream;
}
Tenias razon con historial, debia ser ofstream porque queria escribir en el archivo



eferion, use << en if y en else con la intención de que se guardara el referidoObj[t] sin importar el estado del archivo. Solo que en else primero crea el archivo y luego guarda los datos. Aun no experimento con la recuperación porque no puedo ni guardar los datos
  #7 (permalink)  
Antiguo 16/01/2016, 17:01
 
Fecha de Ingreso: enero-2016
Mensajes: 4
Antigüedad: 8 años, 3 meses
Puntos: 0
Respuesta: Guardar y leer objeto en archivo

Pude solucionarlo. Dentro del struct declare los operator << y >> como friend y en la definición de las funciones quite el scope y añadi la struct como 2da variable. Ya puedo escribir y recuperar los datos. Muchas gracias por su ayuda

Etiquetas: funcion, int, objeto, programa, string
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 02:18.