Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: patilanz en 15 Marzo 2014, 11:33 am



Título: Leer archivos de acceso aleatorio con reinterpet_cast
Publicado por: patilanz en 15 Marzo 2014, 11:33 am
Hola en este codigo:
Código
  1. #include "stdafx.h"
  2. #include <iostream>
  3. #include <fstream>
  4. #include <string>
  5. using namespace std;
  6.  
  7. class name{
  8.    string n;
  9. public:
  10.    name(string N=""):n(N){}
  11.    string getName()const{return n;}
  12. };
  13.  
  14. int _tmain(int argc, _TCHAR* argv[])
  15. {
  16.    fstream file("data.dat",ios::in | ios::out | ios::binary);
  17.    name N;
  18.    file.seekg(0);
  19.    file.read(reinterpret_cast<char *>(&N),sizeof(name));
  20.    if(!file.fail())
  21.        cout << "Good!";
  22.    getchar();
  23.  
  24.    return 0;
  25. }

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


Título: Re: Leer archivos de acceso aleatorio con reinterpet_cast
Publicado por: amchacon en 15 Marzo 2014, 11:57 am
Código
  1. 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
  1. #include "stdafx.h"
  2. #include <iostream>
  3. #include <fstream>
  4. using namespace std;
  5.  
  6. class name
  7. {
  8.    char n[1000];
  9. public:
  10.   // name(string N=""):n(N) {}
  11.    char* getName()
  12.    {
  13.        return n;
  14.    }
  15. };
  16.  
  17. int _tmain(int argc, _TCHAR* argv[])
  18. {
  19.    fstream file("data.dat",ios::in | ios::out | ios::binary);
  20.    name N;
  21.    file.read(N.getName(),1000);
  22.    if(!file.fail())
  23.        cout << "Good!";
  24.    getchar();
  25.  
  26.    return 0;
  27. }
  28.  

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.


Título: Re: Leer archivos de acceso aleatorio con reinterpet_cast
Publicado por: patilanz en 15 Marzo 2014, 13:02 pm
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



Título: Re: Leer archivos de acceso aleatorio con reinterpet_cast
Publicado por: ivancea96 en 15 Marzo 2014, 13:09 pm
String es una clase. Para modificar su array de chars, has de hacerlo mediante los operadres y funciones que string te ofrece.


Título: Re: Leer archivos de acceso aleatorio con reinterpet_cast
Publicado por: amchacon en 15 Marzo 2014, 13:20 pm
Y 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.

pero 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).

Si es asi como lo puedo guardar en un archivo?
Crea este método en la clase:
Código
  1. void setNombre(string &texto)
  2. {
  3.   n = texto;
  4. }

Y lee el nombre con el operador >> que para eso está (o bien, getline si es una línea entera):
Código
  1. fstream file("data.dat",ios::in | ios::out);
  2. Name N;
  3.  
  4. string aux;
  5. file>>aux;
  6.  
  7. N.setNombre(aux);


Título: Re: Leer archivos de acceso aleatorio con reinterpet_cast
Publicado por: patilanz en 15 Marzo 2014, 14:51 pm
La clase name era simplemente por probar, la clase que de verdad queria poner en un archivo es esta:

Código
  1. class item{
  2. public:
  3. item(){ID=0;}
  4. item(int,string,unsigned short int num,double);
  5. item(const item &);
  6.  
  7. int showId() const {return ID;}
  8.  
  9. void changeName(string Name);
  10. string getName() const {return name;}
  11. void changeNum(unsigned short int Num);
  12. unsigned short int getNum()const{return num;}
  13.  
  14. void changeMoney(double Money);
  15. double getMoney() const {return money;}
  16.  
  17. int getId()const{return ID;}
  18. private:
  19. int ID;
  20. string name;
  21. unsigned short int num;
  22. double money;
  23. };

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


Título: Re: Leer archivos de acceso aleatorio con reinterpet_cast
Publicado por: amchacon en 15 Marzo 2014, 15:02 pm
Revisa la clase que hay un método muy interesante:
Código
  1. void changeName(string Name);
Blanco y en botella. Usa ese método para cambiar el nombre. Problema resuelto.

Código
  1. fstream file("data.dat",ios::in | ios::out);
  2. item N;
  3.  
  4. string aux;
  5. file>>aux;
  6.  
  7. N.changeName(aux);

Citar
Porque 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.


Título: Re: Leer archivos de acceso aleatorio con reinterpet_cast
Publicado por: patilanz en 15 Marzo 2014, 15:27 pm
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
  1. file.seekg((sizeof(int)+1000+sizeof(unsigned short int)+sizeof(double))
  2. file.read(id,sizeof(int))*numero_de_registro);//id=int
  3. file.read(name,1000);//name=char[1000]
  4. ...
  5.  

?

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
  1. char id[sizeof(int)];
  2. file.read(id,sizeof(int));


Título: Re: Leer archivos de acceso aleatorio con reinterpet_cast
Publicado por: amchacon en 15 Marzo 2014, 16:48 pm
Haz lo siguiente, definete esta funcion en la clase:

Código
  1. void WriteInFile(fstream &file)
  2. {
  3.    file.write((char*)&ID,sizeof(int));
  4.    file<<name<<' ';
  5.    file.write((char*)&num,sizeof(unsigned short));
  6.    file.write((char*)&money,sizeof(double));
  7. }

Y para leer lo mismo pero al reves:

Código
  1. void ReadInFile(fstream &file)
  2. {
  3.    file.read((char*)&ID,sizeof(int));
  4.    file>>name;
  5.    file.read((char*)&num,sizeof(unsigned short));
  6.    file.read((char*)&money,sizeof(double));
  7. }

Lectura/escritura 100% binaria. Supongo que es lo que querías.


Título: Re: Leer archivos de acceso aleatorio con reinterpet_cast
Publicado por: patilanz en 24 Marzo 2014, 20:32 pm
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
  1. fstream file("data.dat",ios::out | ios::binary);
  2. name n;
  3. char text[100]={"cosa"};
  4. int numero=2;
  5. file << text << ' ';
  6. file.write((char*)&numero,sizeof(int));

Código
  1. fstream file("data.dat",ios::in | ios::binary);
  2. name n;
  3. char text[100];
  4. int numero;
  5. file >> text;
  6. 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


Título: Re: Leer archivos de acceso aleatorio con reinterpet_cast
Publicado por: amchacon en 24 Marzo 2014, 21:57 pm
Hola lo probé pero al abrir el archivo con notepad me muestra el texto normal y corriente, así debería de ser en binario?
Por supuesto.

Las variables no deberías verlas, el texto sí.

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

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

Código
  1. fstream file("data.dat",ios::in | ios::binary);
  2. name n;
  3. char text[100];
  4. int numero;
  5. file >> text;
  6. 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
Pues la sintaxis es correcta.

Aunque yo lo haría con ifstream y ofstream. Sin poner ninguna opción


Título: Re: Leer archivos de acceso aleatorio con reinterpet_cast
Publicado por: patilanz en 24 Marzo 2014, 22:12 pm
Si no pones ninguna opción se te va el binario ?
Lo del numero puede ser por (char*)&numero ?? Es que debería de funcionar.

También probé con fstream i ofstream pero tampoco:

Código
  1. ifstream file("data.dat",ios::binary);
  2. ofstream file("data.bat",ios::binary);


Título: Re: Leer archivos de acceso aleatorio con reinterpet_cast
Publicado por: amchacon en 24 Marzo 2014, 22:17 pm
Si no pones ninguna opción se te va el binario ?
Yo solo sé que funciona, tanto en modo texto como en modo binario.

Lo del numero puede ser por (char*)&numero ?? Es que debería de funcionar.
Nop, esa sintaxis es correcta.

Creo que el problema esque al leer el texto no se salta el espacio. Prueba a poner un file.ignore() para que se salte el espacio delimitador.


Título: Re: Leer archivos de acceso aleatorio con reinterpet_cast
Publicado por: patilanz en 24 Marzo 2014, 23:13 pm
Si efectivamente era el espacio. Muchas gracias pero porque 2 era 544 a que numero corresponde ?