 |
Club Builder Foro de C++Builder en español
|
| Ver tema anterior :: Ver tema siguiente |
| Autor |
Mensaje |
ifrit Master


Registrado: 12 Jun 2007Mensajes: 509Ubicación: La Habana, Cuba
|
Publicado: Mar 27 Abr, 2010 9:56 pm Asunto: ficheros binarios y estructuras |
|
|
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 |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Mie 28 Abr, 2010 12:16 am Asunto: |
|
|
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 |
|
 |
ifrit Master


Registrado: 12 Jun 2007Mensajes: 509Ubicación: La Habana, Cuba
|
Publicado: Mie 28 Abr, 2010 12:36 am Asunto: |
|
|
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 |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Mie 28 Abr, 2010 8:53 am Asunto: |
|
|
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 |
|
 |
ifrit Master


Registrado: 12 Jun 2007Mensajes: 509Ubicación: La Habana, Cuba
|
Publicado: Mie 28 Abr, 2010 1:13 pm Asunto: |
|
|
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 |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Mie 28 Abr, 2010 2:31 pm Asunto: |
|
|
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 |
|
 |
ifrit Master


Registrado: 12 Jun 2007Mensajes: 509Ubicación: La Habana, Cuba
|
Publicado: Mie 28 Abr, 2010 2:48 pm Asunto: |
|
|
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 |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Mie 28 Abr, 2010 3:24 pm Asunto: |
|
|
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 |
|
 |
ifrit Master


Registrado: 12 Jun 2007Mensajes: 509Ubicación: La Habana, Cuba
|
Publicado: Lun 03 May, 2010 6:02 pm Asunto: |
|
|
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 |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Lun 03 May, 2010 8:50 pm Asunto: |
|
|
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 |
|
 |
ifrit Master


Registrado: 12 Jun 2007Mensajes: 509Ubicación: La Habana, Cuba
|
Publicado: Lun 03 May, 2010 9:40 pm Asunto: |
|
|
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 |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Lun 03 May, 2010 11:50 pm Asunto: |
|
|
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 |
|
 |
ifrit Master


Registrado: 12 Jun 2007Mensajes: 509Ubicación: La Habana, Cuba
|
Publicado: Mar 04 May, 2010 12:01 am Asunto: |
|
|
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 |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Mar 04 May, 2010 10:59 am Asunto: |
|
|
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 |
|
 |
ifrit Master


Registrado: 12 Jun 2007Mensajes: 509Ubicación: La Habana, Cuba
|
Publicado: Mar 04 May, 2010 1:23 pm Asunto: |
|
|
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 |
|
 |
|
|
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
|
© 2002–2026 Club Builder · Funciona con phpBB.
|