Leer archivos de acceso aleatorio con reinterpet_cast

Iniciado por patilanz, 15 Marzo 2014, 11:33 AM

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

patilanz

Hola en este codigo:
Código (cpp) [Seleccionar]
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

class name{
    string n;
public:
    name(string N=""):n(N){}
    string getName()const{return n;}
};

int _tmain(int argc, _TCHAR* argv[])
{
    fstream file("data.dat",ios::in | ios::out | ios::binary);
    name N;
    file.seekg(0);
    file.read(reinterpret_cast<char *>(&N),sizeof(name));
    if(!file.fail())
        cout << "Good!";
    getchar();
   
    return 0;
}


Despues de ejecutar un programa para crear el archivo he insertar en el la clase name simplemente por probar porque pasa esto y ahora en este programa cuando termina creo que se ejecuta el destructor de file y me lanza un error de infraccion de acceso de memoria

Excepción no controlada en 0x51DDCCC8 (msvcp110d.dll) en Files_random_acces.exe: 0xC0000005: Infracción de acceso al leer la ubicación 0x01278B9C.


Como solucionar esto?

Saludos

amchacon

Código (cpp) [Seleccionar]
file.seekg(0);
¿Para que pones esto? Por defecto siempre se empieza en la posición cero.

Y en cuanto al error, en un string no puedes escribir directamente. Tienes que llamar a sus métodos/operadores y ellos se encargan de hacer sus gestiones con la memoria dinámica.

Podría funcionar así:

Código (cpp) [Seleccionar]
#include "stdafx.h"
#include <iostream>
#include <fstream>
using namespace std;

class name
{
   char n[1000];
public:
  // name(string N=""):n(N) {}
   char* getName()
   {
       return n;
   }
};

int _tmain(int argc, _TCHAR* argv[])
{
   fstream file("data.dat",ios::in | ios::out | ios::binary);
   name N;
   file.read(N.getName(),1000);
   if(!file.fail())
       cout << "Good!";
   getchar();

   return 0;
}


Aún así me parece una práctica muy poco apropiada y poco práctica.

PD: ¿Que compilador usas? Lo de t_main me llama la atención.
Por favor, no me manden MP con dudas. Usen el foro, gracias.

¡Visita mi programa estrella!

Rar File Missing: Esteganografía en un Rar

patilanz

Hola gracias por tu respuesta.
pero deberia de funcionar con reinterpet_cast. Y lo de string no se puede guardar con una clase porque tiene memoria dinamica ? Si es asi como lo puedo guardar en un archivo?

Utilizo visual studio 2012.

Saludos


ivancea96

String es una clase. Para modificar su array de chars, has de hacerlo mediante los operadres y funciones que string te ofrece.

amchacon

Cita de: patilanz en 15 Marzo 2014, 13:02 PMY lo de string no se puede guardar con una clase porque tiene memoria dinamica ?
Si que se puede, lo que no puedes hacer es escribir en su memoria a lo bruto. Para empezar porque lo que estas haciendo es sobreescribir su puntero (la clase string no guarda el texto, sino el puntero donde tiene reservado el texto).

El encapsulamiento y el que haya métodos privados y públicos se hizo por algo. Si quieres adceder al contenido del string, usa sus métodos, si quieres modificarlo usa sus métodos tambien.

Cita de: patilanz en 15 Marzo 2014, 13:02 PMpero deberia de funcionar con reinterpet_cast. Y lo de string no se puede guardar con una clase porque tiene memoria dinamica ?
No debería, ya no solo por lo que te he dicho antes sino porque le has pasado el objeto entero (que tiene más cosas que la clase string).

Yo soy muy poco partidario de usar un reinterpet_cast para un objeto, lo ideal es definir un operador char* en la clase. Aunque en este ejemplo no lo necesitas (sigue leyendo).

Cita de: patilanz en 15 Marzo 2014, 13:02 PMSi es asi como lo puedo guardar en un archivo?
Crea este método en la clase:
Código (cpp) [Seleccionar]
void setNombre(string &texto)
{
  n = texto;
}


Y lee el nombre con el operador >> que para eso está (o bien, getline si es una línea entera):
Código (cpp) [Seleccionar]
fstream file("data.dat",ios::in | ios::out);
Name N;

string aux;
file>>aux;

N.setNombre(aux);
Por favor, no me manden MP con dudas. Usen el foro, gracias.

¡Visita mi programa estrella!

Rar File Missing: Esteganografía en un Rar

patilanz

La clase name era simplemente por probar, la clase que de verdad queria poner en un archivo es esta:

Código (cpp) [Seleccionar]
class item{
public:
item(){ID=0;}
item(int,string,unsigned short int num,double);
item(const item &);

int showId() const {return ID;}

void changeName(string Name);
string getName() const {return name;}
void changeNum(unsigned short int Num);
unsigned short int getNum()const{return num;}

void changeMoney(double Money);
double getMoney() const {return money;}

int getId()const{return ID;}
private:
int ID;
string name;
unsigned short int num;
double money;
};


Si cambio el string por char [1000] como lo hago sin usar reinterpet_cast.
Porque no te gusta utilizar reinterpet_cast ?

Para leer la clase  seria algo como guardar todos sus variables privadas con un tamano fijo y luego recuperar los uno a uno y meterlos en una clase nueva con sus metodos public ?

Saludos

amchacon

#6
Revisa la clase que hay un método muy interesante:
Código (cpp) [Seleccionar]
void changeName(string Name);
Blanco y en botella. Usa ese método para cambiar el nombre. Problema resuelto.

Código (cpp) [Seleccionar]
fstream file("data.dat",ios::in | ios::out);
item N;
   
string aux;
file>>aux;
   
N.changeName(aux);


CitarPorque no te gusta utilizar reinterpet_cast ?
Transformar objetos a datos primitivos es una barbaridad, definirte operadores de conversión es más seguro y efectivo.
Por favor, no me manden MP con dudas. Usen el foro, gracias.

¡Visita mi programa estrella!

Rar File Missing: Esteganografía en un Rar

patilanz

#7
Ya se que tengo el metodo para cambiar el nombre pero no me refiera a esto si no a que cuando se guardan y quiero que sea un conjunto de informacion con tamano fijo para reemplzar con una posicion exacta tengo que sumar los sizeof() de todos las variables de la clase y guardar los uno en uno y luego al leer los tengo que usar algo así:

Código (cpp) [Seleccionar]
file.seekg((sizeof(int)+1000+sizeof(unsigned short int)+sizeof(double))
file.read(id,sizeof(int))*numero_de_registro);//id=int
file.read(name,1000);//name=char[1000]
...


?

Y para escribir lo mismo.

O también si hago una función que convierte todos los datos en un tipo exacto preparado para ser guardado de una vez en el file. O si hay otro metodo mejor?


@Edit: Me acabo de dar cuenta de que file.read() tiene que ser char* el primer argumento y tengo que convertir el int a char*.

Algo como esto:
Código (cpp) [Seleccionar]
char id[sizeof(int)];
file.read(id,sizeof(int));

amchacon

#8
Haz lo siguiente, definete esta funcion en la clase:

Código (cpp) [Seleccionar]
void WriteInFile(fstream &file)
{
   file.write((char*)&ID,sizeof(int));
   file<<name<<' ';
   file.write((char*)&num,sizeof(unsigned short));
   file.write((char*)&money,sizeof(double));
}


Y para leer lo mismo pero al reves:

Código (cpp) [Seleccionar]
void ReadInFile(fstream &file)
{
   file.read((char*)&ID,sizeof(int));
   file>>name;
   file.read((char*)&num,sizeof(unsigned short));
   file.read((char*)&money,sizeof(double));
}


Lectura/escritura 100% binaria. Supongo que es lo que querías.
Por favor, no me manden MP con dudas. Usen el foro, gracias.

¡Visita mi programa estrella!

Rar File Missing: Esteganografía en un Rar

patilanz

#9
Hola lo probé pero al abrir el archivo con notepad me muestra el texto normal y corriente, así debería de ser en binario?

Y al probar lo que me dijiste para guardar un char[100] y un int probe esto:

Código (cpp) [Seleccionar]
fstream file("data.dat",ios::out | ios::binary);
name n;
char text[100]={"cosa"};
int numero=2;
file << text << ' ';
file.write((char*)&numero,sizeof(int));


Código (cpp) [Seleccionar]
fstream file("data.dat",ios::in | ios::binary);
name n;
char text[100];
int numero;
file >> text;
file.read((char*)&numero,sizeof(int));


El texto me lo hace bien pero el por ejemplo para 2 me devuelve 544 y para 54 13856 y no se porque?

Saludos