Grabar estructura en archivo [lenguaje C] [Windows 7]

Iniciado por DanielPy, 9 Marzo 2015, 18:41 PM

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

DanielPy

Hola gente.
Nuevamente con dudas que no logro resolver con el manual ni con consultas en la web (con este último tal vez lo lograría pero nunca encuentro cosas tan avanzadas como las de este foro, gracias al gran conocimiento de los que responden).-
Mi consulta es, la única manera de grabar los datos en disco es con fprintf y detallando uno por uno los campos de la estructura o hay alguna manera de hacerlo  más conciso,  realmente ¿si la estructura tiene 20 campos hay que detallarlo uno por uno?- 
Por último si alguien tiene mucho tiempo y desea darme alguna sugerencia para mejorar el código, Danielito agradecido.-


#include <stdio.h>
#include <windows.h>
#include <string.h>

typedef struct{
int orden;
char nombre[30];
char apellido[30];
char direccion[30];
int numCalle;
char ciudad[30];
char provincia[30];
}Cliente;

void mosDtos(Cliente *ptrCliente);
void ingDtos(Cliente *ptrCliente);
void opciones(Cliente *ptrCliente);
void graDtos(Cliente *ptrCliente);

int main(void){
FILE *ptrCte;
Cliente datos  = {0, "\0", "\0", "\0", 0, "\0", "\0"};

if(( ptrCte = fopen( "archivo.txt", "w" )) == NULL ){
perror(" archivo.txt ");
}
else{
ingDtos(&datos);
fclose(ptrCte);
}

getchar();
return 0;
}

void mosDtos(Cliente *ptrCliente){
system("cls");

printf("\n\n == Introduzca datos del cliente \"Ningun campo puede permanecer vacio\" ==");
printf( "\n\n =========================================================================\n" );
printf("\n Orden...............: %d", ptrCliente->orden);
printf("\n Nombre..............: %s", ptrCliente->nombre);
printf("\n Apellido............: %s", ptrCliente->apellido);
printf("\n Direccion...........: %s", ptrCliente->direccion);
printf("\n Altura de la calle..: %d", ptrCliente->numCalle);
printf("\n Ciudad..............: %s", ptrCliente->ciudad);
printf("\n Provincia...........: %s", ptrCliente->provincia);
printf( "\n\n =========================================================================\n" );
}

void ingDtos(Cliente *ptrCliente){
int ok, ch;
char *p = NULL;

do{
mosDtos(ptrCliente);
printf("\n Orden...............: ");
ok = scanf("%d", &ptrCliente->orden) == 1 && ptrCliente->orden >= 1;
while ((ch = getchar()) != EOF && ch != '\n');
}while(!ok);

do{
mosDtos(ptrCliente);
printf("\n Nombre..............: ");
fgets(ptrCliente->nombre, 30, stdin);
if((p=strchr(ptrCliente->nombre, '\n'))){
*p='\0';
}
else{
while((ch = getchar()) !='\n' && ch!=EOF);
}
ok = strlen(ptrCliente->nombre);
}while(!ok);

do{
mosDtos(ptrCliente);
printf("\n Apellido............: ");
fgets(ptrCliente->apellido, 30, stdin);
if((p=strchr(ptrCliente->apellido, '\n'))){
*p='\0';
}
else{
while((ch = getchar()) !='\n' && ch!=EOF);
}
ok = strlen(ptrCliente->apellido);
}while(!ok);

do{
mosDtos(ptrCliente);
printf("\n Direccion...........: ");
fgets(ptrCliente->direccion, 30, stdin);
if((p=strchr(ptrCliente->direccion, '\n'))){
*p='\0';
}
else{
while((ch = getchar()) !='\n' && ch!=EOF);
}
ok = strlen(ptrCliente->direccion);
}while(!ok);

do{
mosDtos(ptrCliente);
printf("\n Altura de la calle..: ");
ok = scanf( "%d", &ptrCliente->numCalle ) == 1 && ptrCliente->numCalle >= 1;
while ((ch = getchar()) != EOF && ch != '\n');
}while(!ok);

do{
mosDtos(ptrCliente);
printf("\n Ciudad..............: ");
fgets(ptrCliente->ciudad, 30, stdin);
if((p=strchr(ptrCliente->ciudad, '\n'))){
*p='\0';
}
else{
while((ch = getchar()) !='\n' && ch!=EOF);
}
ok = strlen(ptrCliente->ciudad);
}while(!ok);

do{
mosDtos(ptrCliente);
printf("\n Provincia...........: ");
fgets(ptrCliente->provincia, 30, stdin);
if((p=strchr(ptrCliente->provincia, '\n'))){
*p='\0';
}
else{
while((ch = getchar()) !='\n' && ch!=EOF);
}
ok = strlen(ptrCliente->provincia);
}while(!ok);
mosDtos(ptrCliente);

opciones(ptrCliente);
}

void opciones(Cliente *ptrCliente){
int opcion, ok;
char ch;

do{
mosDtos(ptrCliente);
printf("\n ========= Opciones =========");
printf("\n 1 - Grabar en disco.");
printf("\n 2 - Introducir nuevamente los datos.");
printf("\n 3 - Finalizar.");

printf("\n\n Ingrece opci%cn....: ", 162);
ok = scanf("%d", &opcion) == 1 && opcion >= 1 && opcion <= 3;
while ((ch = getchar()) != EOF && ch != '\n');
}while(!ok);

if(opcion == 1){
graDtos(ptrCliente);
}
else if(opcion == 2){
ptrCliente->orden = 0;
strcpy(ptrCliente->nombre, "\0");
strcpy(ptrCliente->apellido, "\0");
strcpy(ptrCliente->direccion, "\0");
ptrCliente->numCalle = 0;
strcpy(ptrCliente->ciudad, "\0");
strcpy(ptrCliente->provincia, "\0");

mosDtos(ptrCliente);
ingDtos(ptrCliente);
}

}

void graDtos(Cliente *ptrCliente){

}



Una cosita más, no desconozco que las validaciones no son del todo eficiente, pero eso lo soluciono luego.-

Saludos y gracias por el tiempo.
Daniel
abraza las cosas y personas malas como si fueran tu mas preciada joya,Son tus mas grandes maestros de paciencia sabiduría y amor
y cuando lo abrazas dejan de causar dolor.-

ivancea96

En memoria, una estructura que yo sepa se guarda en un bloquede memoria, contiguo. Por tanto, bastaría hacer un cast a char*.

Pero yo no haría eso, principalmente, porque una estructura puede guardar punteros, y porque puede ser más problemático.

Basta hacer una función que serialice la estructura. Sean 1, 2 o 10 campos, la función no se va a alargar, no hay razón para evitarla.

BloodSharp

Cita de: DanielC# en  9 Marzo 2015, 18:41 PMMi consulta es, la única manera de grabar los datos en disco es con fprintf y detallando uno por uno los campos de la estructura o hay alguna manera de hacerlo  más conciso,  realmente ¿si la estructura tiene 20 campos hay que detallarlo uno por uno?

No, para esciribir toda una estructura de una tenés fwrite...


B#



DanielPy

Hola.
ivancea96, como conozco que no te gusta demasiado poner código no te voy a pedir que lo hagas, como siempre y seguramente la tuya es una muy buena solución, me voy a documentar sobre
Citar"Basta hacer una función que serialice la estructura. Sean 1, 2 o 10 campos, la función no se va a alargar, no hay razón para evitarla."
, no tengo conocimientos sobre el particular.-
BloodSharp,  voy a practicar con la función que propones.-
Gracias a los 2 por el tiempo.-

Saludos.
Daniel
abraza las cosas y personas malas como si fueran tu mas preciada joya,Son tus mas grandes maestros de paciencia sabiduría y amor
y cuando lo abrazas dejan de causar dolor.-


DanielPy

Hola BloodSharp.
Si te toparas en un caso como el mío me podrías decir como lo solucionarías, el caso es que estoy buscando desde que ivancea96 me sugirió serealizar los campos de la estructura y no encuentro ni un mísero ej. o por lo menos al alcance de mis conocimientos, espero puedas(an) ayudarme.

Saludos.
Daniel
abraza las cosas y personas malas como si fueran tu mas preciada joya,Son tus mas grandes maestros de paciencia sabiduría y amor
y cuando lo abrazas dejan de causar dolor.-

BloodSharp

Cita de: DanielC# en 10 Marzo 2015, 22:28 PMHola BloodSharp.
Si te toparas en un caso como el mío me podrías decir como lo solucionarías, el caso es que estoy buscando desde que ivancea96 me sugirió serealizar los campos de la estructura y no encuentro ni un mísero ej. o por lo menos al alcance de mis conocimientos, espero puedas(an) ayudarme.

Saludos.
Daniel

Mmm, en realidad depende de como uno lo quiera grabar los datos y la cantidad de estructuras de objetos quieras guardar... En mi caso yo primero cifraría los datos de la estructura con una clave (cosa que en realidad es opcional y para complicar la lectura de como están guardados los datos, sobretodo en los strings, dado a que si no están cifrados aparecen tal cúal están como si fuera en texto plano) y luego escribiría la estructura entera cifrada.

Ejemplo usando tu código:

FILE *ptrCte;//Archivo ya abierto
int graDtos(Cliente *ptrCliente)
{
   return fwrite(ptrCliente,sizeof(Cliente),1,ptrCte);
}

int leerDatos(Cliente *ptrCliente)
{
   return fread(ptrCliente,sizeof(Cliente),1,ptrCte);
}

char *szClave="unaClave";
int graDtosCifrados(Cliente *ptrCliente)
{
   Cliente clienteCifrado;
   memcpy(&clienteCifrado,ptrCliente,sizeof(Cliente));
   //No cifro la estructura original por si la necesito luego
   RutinaParaCifrar(&clienteCifrado,sizeof(Cliente),szClave,strlen(szClave));
   return fwrite(clienteCifrado,sizeof(Cliente),1,ptrCte);
}

int leerDatosCifrados(Cliente *ptrCliente)
{
   int bytesleidos;
   Cliente clienteDescifrado;
   byteleidos=fread(clienteDescifrado,sizeof(Cliente),1,ptrCte);
   RutinaParaCifrar(&clienteDescifrado,sizeof(Cliente),szClave,strlen(szClave));
   memcpy(ptrCliente,&clienteDescifrado,sizeof(Cliente));
   return bytesleidos;
}



B#



DanielPy

Hola BloodSharp.
Muchas gracias por el código.-
Te explico, como por el momento me resultaba muy difícil entender tú código y para no molestarte tanto me puse a buscar nuevamente en internet y encontré más de un video que ponían ejemplos con estructuras con campos de diferentes tipos, pude implementarlos y funcionan a la perfección, evidentemente el programa que puse es un poco largo y no supe explicarme lo suficiente.-
Bueno retomando el nuevo código les pido una manito para solucionar 2 cositas que me quedan pendiente:
La  primera es ¿Cómo puedo hacer para imprimir el último dato ingresado? Es que quiero ingresar "matricula" en orden, o sea 1,2,3,4,5,6,7... para ello necesito ver en pantalla el último ingreso, obviamente sería interesante que este campo sea de sólo lectura y que se rellenara sólo con la última matricula + 1, pero bueno para mis conocimiento sobre archivos en C con que me muestre en pantalla el último es suficiente.-
Lo último es un inconveniente con el bucle while, siempre me duplica el último dato.-
Esta vez parece todo más sencillo y fácil de entender.-       

#include <stdio.h>

struct registro{
char nombre[30];
int matricula;
}est;

int main(void){
FILE *ptrEst;
int ch;

if( (ptrEst = fopen( "ingles.txt" , "a+" )) == NULL ){
printf( "\n\n ERROR, no se pudo abrir el archivo..." );
}
else{
// fread(&est, sizeof(est), 1, ptrEst);
// printf( "\n\n Ultimo ingreso....: %d - %s \n", est.matricula, est.nombre );

printf( "\n\n Nombre.........:");
gets(est.nombre);

printf( "\n Matricula......:" );
scanf( "%d", &est.matricula );
while ((ch = getchar()) != EOF && ch != '\n');

fwrite(&est, sizeof(est), 1, ptrEst);

rewind(ptrEst);

printf( "\n\n Listado completo\n" );
while( !feof(ptrEst) ){
fread(&est, sizeof(est), 1, ptrEst);
printf( " %d - %s \n", est.matricula, est.nombre );
}

fclose(ptrEst);
}

getchar();
return 0;
}

Gracias ivancea96 por tú ayuda.-
Saludos.
Daniel
abraza las cosas y personas malas como si fueran tu mas preciada joya,Son tus mas grandes maestros de paciencia sabiduría y amor
y cuando lo abrazas dejan de causar dolor.-

BloodSharp

//Asumiendo que tenés al menos una entrada de estructura ya previamente guardada...
int ultimaMatricula;
fseek(ptrEst,(-1)*sizeof(int), SEEK_END);
fread(&ultimaMatricula,sizeof(int),1,ptrEst);


printf( "\n\n Listado completo\n" );
fread(&est, sizeof(est), 1, ptrEst);
while( !feof(ptrEst) )
printf( " %d - %s \n", est.matricula, est.nombre ),
fread(&est, sizeof(est), 1, ptrEst);



B#



DanielPy

Hola.
No me funciona ninguno de los 2 códigos, si los utilizo, el primero no me deja agregar registros, pero no desesperemos, teniendo las funciones correctas (que seguramente lo son) voy a buscar en la web para hacer que funcione.-

Saludos.
Daniel   
abraza las cosas y personas malas como si fueran tu mas preciada joya,Son tus mas grandes maestros de paciencia sabiduría y amor
y cuando lo abrazas dejan de causar dolor.-