Club Builder - Foros de discusión Club Builder
Foro de C++Builder en español
 
 FAQFAQ   BuscarBuscar   MiembrosMiembros   Grupos de UsuariosGrupos de Usuarios   RegistrarseRegistrarse 
 PerfilPerfil   Entra para ver tus mensajes privadosEntra para ver tus mensajes privados   EntrarEntrar 

ficheros binarios y estructuras
Ir a página 1, 2  Siguiente
 
Publicar nuevo tema   Responder al tema    Foros de discusión -> Consultas
Ver tema anterior :: Ver tema siguiente  
Autor Mensaje
Mensaje    Asunto: ficheros binarios y estructuras Responder citando

Hola amigos estoy intentando almacenar cierta informacion en un fichero utilizando el siguiente ejemplo:

<code>
#include <iostream>
#include <fstream>
#include <cstring>

using namespace std;

struct tipoRegistro {
char nombre[32];
int edad;
float altura;
};

int main() {
tipoRegistro pepe;
tipoRegistro pepe2;
ofstream fsalida("prueba.dat",
ios::out | ios::binary);

strcpy(pepe.nombre, "Jose Luis");
pepe.edad = 32;
pepe.altura = 1.78;

fsalida.write(reinterpret_cast<char>(&pepe),
sizeof(tipoRegistro));
fsalida.close();

ifstream fentrada("prueba.dat",
ios::in | ios::binary);

fentrada.read(reinterpret_cast<char>(&pepe2),
sizeof(tipoRegistro));
cout << pepe2.nombre << endl;
cout << pepe2.edad << endl;
cout << pepe2.altura << endl;
fentrada.close();

return 0;
}
</code>
El cual funciona a la perfeccion
Pero lo que necesito es que el fichero almacene mas de una linea y luego me las devuleva cuando las consulte. Para lo cual intente con:

ofstream fsalida("prueba.dat", ios::app | ios::binary);

y de esta forma me almacena mas de una linea y no me elimina lo que habia anteriormente, pero solo con esto no me basta asi que hice lo siguiente:

for (int i =0 ; i < cantidad de registros almacenados; i++){
fentrada.read(reinterpret_cast<char>(&pepe2),
sizeof(tipoRegistro));
cout << pepe2.nombre << endl;
cout << pepe2.edad << endl;
cout << pepe2.altura << endl;
}

pero solo me muestra el primer registro, quiciera poder mostrar en un Memo todo los registros del fichero con el mismo orden de la estructura, espero haberme hecho entender y que me puedan ayudar
Muchas gracias
_________________
Todos somos ignorantes, lo que no todos ignoramos lo mismo...
Volver arriba
Ver perfil de usuario Enviar mensaje privado Enviar email
Mensaje    Asunto: Responder citando

Yo lo he probado así y funciona:

Código:
//---------------------------------------------------------------------------

#pragma hdrstop

//---------------------------------------------------------------------------

#pragma argsused
#include <fstream.h>
#pragma hdrstop

using namespace std;

struct tipoRegistro {
  char nombre[32];
  int edad;
  float altura;
};

int main() {
  tipoRegistro pepe;
  tipoRegistro pepe2;
  ofstream fsalida("prueba.dat", ios::app | ios::binary);
  strcpy(pepe.nombre, "Jose Luis");
  pepe.edad = 32;
  pepe.altura = 1.78;

  strcpy(pepe2.nombre, "Pepe");
  pepe2.edad = 40;
  pepe2.altura = 2.08;

  fsalida.write((char*)(&pepe),sizeof(tipoRegistro));
  fsalida.write((char*)(&pepe2),sizeof(tipoRegistro));
  fsalida.close();
  ifstream fentrada("prueba.dat", ios::in | ios::binary);

  for (int i =0 ; i < 2; i++){
    fentrada.read((char*)&pepe2, sizeof(tipoRegistro));
    cout << pepe2.nombre << endl;
    cout << pepe2.edad << endl;
    cout << pepe2.altura << endl;
  }
  fentrada.close();
}


Saludos.
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

Gracias po rresponder scafandra, me parece que de la forma que lo he intentado tra ealgunos problemas, cuando quiera (por ejemplo) almacenar mas datos 10 o 20 personas tendria que crear pepe desde 0 a 20. y tambien poner 20
fsalida.write((char*)(&pepe del 0 al 20),sizeof(tipoRegistro));
me parece que no es la mejor forma, entonces te pregunto, existe una mejor forma de hacer esto, espero que si y que me puedas ayudar
muchas gracias
_________________
Todos somos ignorantes, lo que no todos ignoramos lo mismo...
Volver arriba
Ver perfil de usuario Enviar mensaje privado Enviar email
Mensaje    Asunto: Responder citando

Pues evidentemente no puedes crear tantas variables como elementos o registros quieras tener, máxime cuando puedes no conocer el número por adelantado, entonces la mejor forma sería usar un array de registros de tipo dinámico. Si el tamaño de los registros es invariable (nombre siempre tiene 32 caracteres) entonces el número de registros guardados en un archivo es FileSize/sizeof(tipoRegistro) de esa forma sabes el tamaño del array para leer.

Código:
tipoRegistro* Registros = new tipoRegistro[FileSize/sizeof(tipoRegistro)];
......
delete []  Registros;


Otra forma sería leer todo el archivo en un Buffer al que aplicarías un cast
para convertirlo en un puntero de tipo tipoRegistro* para manejarlo como un array.

En definitiva, tu problema lo solucionas usando punteros.

Saludos.
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

Scafandra, muchas gracias por la ayuda, todo funciona bien.
No obstante me surge una duda, cuando trabajaba de esta forma

strcpy(pepe.nombre, "Jose Luis");
pepe.edad = 32;

el fichero donde se almacenaba la informacion "c:\\prueba.dat" se iva llenando con registros (lineas) segun intrducia los datos; pero como es de esperar yo iva a poner Edits para que el usuario introduciera los datos y me quedo asi


String name = Edit1->Text.c_str();
int eda = StrToInt(Edit2->Text);

strcpy(pepe.nombre, name.c_str());
pepe.edad = eda;

Cuando observe el fichero prueba.dat ahora no importa cuantos datos nuevos introduzca, solo se ve un linea extensa con los datos unos a continuacion del otro y no uno debajo del otro como estaba antes. Esto para nada afecta al programa pero me parecio curioso este nuevo comportamiento, tienes idea de porque ocurre esto?
Muchas gracias
_________________
Todos somos ignorantes, lo que no todos ignoramos lo mismo...
Volver arriba
Ver perfil de usuario Enviar mensaje privado Enviar email
Mensaje    Asunto: Responder citando

En realidad el fichero que estas escribiendo no tiene líneas. Nunca has escrito un endl que sería el cambio de línea. Los registros los escribes de corrido y así los lees. Lo que pasa es que al leer lo haces en bloques del tamaño de un registro y eso te puede dar la impresión de que lees una línea.

Las líneas sólo tienen sentido cuando hablamos de archivos de texto y no en binarios y se definen por un grupo de dos BYTES 0x0D 0x0A.

Saludos.
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

Ok, scafandra, te copie, pero te comento nuevamente que cuando abri el fichero primeramente estaba organizado por lineas segun agregaba personas y luego al poner Edits lo pone todo corrido. Como te dije no hay problemas con esto, era solo una curiosidad, muchas gracias por ayudarme
Saludos
_________________
Todos somos ignorantes, lo que no todos ignoramos lo mismo...
Volver arriba
Ver perfil de usuario Enviar mensaje privado Enviar email
Mensaje    Asunto: Responder citando

Bueno, es posible que el ultimo de los datos numéricos hicieran concordar con los Bytes mencionados (0x0D 0x0A) y provocaran el salto de línea al visualizarlo con el notepad, por ejemplo...

Saludos.
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

Hola scafandra
Al seguri trabajando con los fichero me han surgid nuevas dudas; por ejemplo como editar los valores y como eliminarlos. Par editarlos lo que hice fue lo siguiente:

Código:

Memo1->Clear();
 fstream fsalida("c:\\prueba.dat", ios::in | ios::out | ios::binary);

   //obtenemos el tamaño del fichero para saber numero de registros
   fsalida.seekg(0, ios::end);
   int pos = fsalida.tellg();
   int count = pos / sizeof(tipoRegistro);

   //comenzamos a leer al comienzo del fichero
   fsalida.seekg(0, ios::beg);

   for(i = 0; i < count; i++) {

      fsalida.read((char*)&pepe, sizeof(tipoRegistro));

      //preguntamos por un valor existente para modificar
      if (String(pepe.nombre) == "michel"){

        fsalida.seekp(i*sizeof(tipoRegistro), ios::beg);
        strcpy(pepe.nombre, "nuevo_nombre");
        pepe.edad = 12;
        fsalida.write((char*)(&pepe),sizeof(tipoRegistro));
      }
   }
  fsalida.close();


pero aun no se como poder eliminar el registro que yo mande a buscar, me explico para editar busco "michel" y lo edito, para eliminar necesitaria hacer lo mismo, buscar por un nombre y luego eliminarlo. Intente pasarlo todo a un StringList, pero este no me carga todo el fichero.
Me podrias ayudar por favor? Gracias
_________________
Todos somos ignorantes, lo que no todos ignoramos lo mismo...
Volver arriba
Ver perfil de usuario Enviar mensaje privado Enviar email
Mensaje    Asunto: Responder citando

Un StringList no te sirve porque tienes datos binarios, concretamente los numéricos.

Creo que lo mejor es el uso de un array de punteros. Tienes el objeto TList que te sirve para manejar ese array de punteros. Cada elemento será un puntero a un registro. Te permite insertar, borrar, añadir...

Sólo tienes que rellenar el TList editar o manejar tus datos, borrar los registros que quieras y guardarlos en disco usando un bucle desde el primero hasta el último registro.

Saludos.
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

scafandra muchas gracias, si no es mucho pedir,me podrias dejar un ejemplo por favor
_________________
Todos somos ignorantes, lo que no todos ignoramos lo mismo...
Volver arriba
Ver perfil de usuario Enviar mensaje privado Enviar email
Mensaje    Asunto: Responder citando

Una rápida aproximación podría ser creando una clase que reúna los elementos que necesitas. Esa clase debe ser capaz de almacenar los registros, Añadir nuevos, borrarlos, Insertar, limpiarse, leer y escribir el fichero con los registros.

Te muestro un ejemplo que he escrito rápidamente y no lo he probado, pero te puede mostrar como hacerlo. Puedes completarlo y añadirle mas funcionalidades.

Código:
#include <fstream.h>
#include <fcntl.h>
#include<io.h>

using namespace std;

struct tipoRegistro {
  char nombre[32];
  int edad;
  float altura;
};

class TRegistros
{
  private:
  TList* List;

  public:
  TRegistros();
  ~TRegistros();

  tipoRegistro& operator [] (int);
  int GetCount();
  void Insert(tipoRegistro& R);
  void Add(tipoRegistro& R);
  void Delete(int);
  void ReadFile(char* FileName);
  void WriteFile(char* FileName);
  void Clear();
};

TRegistros::TRegistros()
{
   List = new TList();
}

TRegistros::~TRegistros()
{
   Clear();
   delete List;
}

// libera todos los registros
void TRegistros::Clear()
{
   for(int n=0; n<List->Count;n++){
     delete List->Items[n];
     List->Items[n] = 0;
   }
   List->Clear();
}

int TRegistros::GetCount()
{
   return List->Count;
}

// Devuelve una referencia a un tipoRegistro pedido.
// Si está fuera de rango devuelve el correspondiente al modulo.
tipoRegistro& TRegistros::operator [] (int i)
{
   return *(tipoRegistro*)List->Items[i%List->Count];
}

void TRegistros::Add(tipoRegistro& R)
{
   tipoRegistro* NewR = new tipoRegistro;
   *NewR = R;
   List->Add(NewR);
}

void TRegistros::Delete(int i)
{
   delete List->Items[i];
   List->Delete(i);
}

// Esto lo puedes hacer con fstream también
void TRegistros::ReadFile(char* FileName)
{
   int File = open(FileName, O_BINARY);
   if(File ==-1) return;

   int Size = filelength(File);
   int Count = Size/sizeof(tipoRegistro);
   tipoRegistro* Items = new tipoRegistro[Count];
   read(File, (void*)Items, Size);
   close(File);
   
   Clear();
   for(int n=0; n<Count; n++)
     Add(Items[n]);
   delete [] Items;
}

// Esto lo puedes hacer con el sistema de bajo nivel también.
void TRegistros::WriteFile(char* FileName)
{
  ofstream fsalida(FileName, ios::trunc | ios::binary);
  for(int n=0; n<List->Count; n++)
    fsalida.write((char*)(List->Items[n]),sizeof(tipoRegistro));
  fsalida.close();
}


Saludos.


Ultima edición por escafandra el Dom 01 Ago, 2010 1:14 pm, editado 5 veces
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

scafandra, muchas gracias por responder, le hechare una ojedad luego, aunque te adelanto que no se nada de nada de clases y ese tema me resulta desconocido. Ya vere en que parte me travo y espero me puedas ayudar nuevamente.
Muchas gracias
_________________
Todos somos ignorantes, lo que no todos ignoramos lo mismo...
Volver arriba
Ver perfil de usuario Enviar mensaje privado Enviar email
Mensaje    Asunto: Responder citando

Pues el uso de esa clase es sencillo:

Código:

// Creo un objeto de la clase TRegistros:
TRegistros Registros;
// Creo un registro:
tipoRegistro Reg;
strcpy(Reg.nombre, "Jose Luis");
Reg.edad = 32;
Reg.altura = 1.78;
// Añado el registro:
Registros.Add(Reg);

//..............
// Escribo archivo
Registros.Write("Prueba.dat");

//.............
// Leo archivo
Registros.Read("Prueba.dat");

//.................
// Edito datos.
Registros[0].edad = 33;

//..................


Saludos.
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

Muchas gracias scafandra, en cuanto lo ponga en practica te comento, nuevamente muchas gracias por toda esta ayuda.
Saludos
_________________
Todos somos ignorantes, lo que no todos ignoramos lo mismo...
Volver arriba
Ver perfil de usuario Enviar mensaje privado Enviar email
Mostrar mensajes de anteriores:   
Cambiar a:  
No puedes publicar temas nuevos en este foro
No puedes responder a temas en este foro
No puedes editar tus mensajes en este foro
No puedes borrar tus mensajes en este foro
No puedes votar en las encuestas de este foro


Hosting WordPress Indedmedia desde 3,99 €
© 2002–2026 Club Builder · Funciona con phpBB.