Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: DanielPy en 9 Marzo 2015, 18:41 pm



Título: Grabar estructura en archivo [lenguaje C] [Windows 7]
Publicado por: DanielPy en 9 Marzo 2015, 18:41 pm
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.-


Código
  1. #include <stdio.h>
  2. #include <windows.h>
  3. #include <string.h>
  4.  
  5. typedef struct{
  6. int orden;
  7. char nombre[30];
  8. char apellido[30];
  9. char direccion[30];
  10. int numCalle;
  11. char ciudad[30];
  12. char provincia[30];
  13. }Cliente;
  14.  
  15. void mosDtos(Cliente *ptrCliente);
  16. void ingDtos(Cliente *ptrCliente);
  17. void opciones(Cliente *ptrCliente);
  18. void graDtos(Cliente *ptrCliente);
  19.  
  20. int main(void){
  21. FILE *ptrCte;
  22. Cliente datos  = {0, "\0", "\0", "\0", 0, "\0", "\0"};
  23.  
  24. if(( ptrCte = fopen( "archivo.txt", "w" )) == NULL ){
  25. perror(" archivo.txt ");
  26. }
  27. else{
  28. ingDtos(&datos);
  29. fclose(ptrCte);
  30. }
  31.  
  32. return 0;
  33. }
  34.  
  35. void mosDtos(Cliente *ptrCliente){
  36. system("cls");
  37.  
  38. printf("\n\n == Introduzca datos del cliente \"Ningun campo puede permanecer vacio\" ==");
  39. printf( "\n\n =========================================================================\n" );
  40. printf("\n Orden...............: %d", ptrCliente->orden);
  41. printf("\n Nombre..............: %s", ptrCliente->nombre);
  42. printf("\n Apellido............: %s", ptrCliente->apellido);
  43. printf("\n Direccion...........: %s", ptrCliente->direccion);
  44. printf("\n Altura de la calle..: %d", ptrCliente->numCalle);
  45. printf("\n Ciudad..............: %s", ptrCliente->ciudad);
  46. printf("\n Provincia...........: %s", ptrCliente->provincia);
  47. printf( "\n\n =========================================================================\n" );
  48. }
  49.  
  50. void ingDtos(Cliente *ptrCliente){
  51. int ok, ch;
  52. char *p = NULL;
  53.  
  54. do{
  55. mosDtos(ptrCliente);
  56. printf("\n Orden...............: ");
  57. ok = scanf("%d", &ptrCliente->orden) == 1 && ptrCliente->orden >= 1;
  58. while ((ch = getchar()) != EOF && ch != '\n');
  59. }while(!ok);
  60.  
  61. do{
  62. mosDtos(ptrCliente);
  63. printf("\n Nombre..............: ");
  64. fgets(ptrCliente->nombre, 30, stdin);
  65. if((p=strchr(ptrCliente->nombre, '\n'))){
  66. *p='\0';
  67. }
  68. else{
  69. while((ch = getchar()) !='\n' && ch!=EOF);
  70. }
  71. ok = strlen(ptrCliente->nombre);
  72. }while(!ok);
  73.  
  74. do{
  75. mosDtos(ptrCliente);
  76. printf("\n Apellido............: ");
  77. fgets(ptrCliente->apellido, 30, stdin);
  78. if((p=strchr(ptrCliente->apellido, '\n'))){
  79. *p='\0';
  80. }
  81. else{
  82. while((ch = getchar()) !='\n' && ch!=EOF);
  83. }
  84. ok = strlen(ptrCliente->apellido);
  85. }while(!ok);
  86.  
  87. do{
  88. mosDtos(ptrCliente);
  89. printf("\n Direccion...........: ");
  90. fgets(ptrCliente->direccion, 30, stdin);
  91. if((p=strchr(ptrCliente->direccion, '\n'))){
  92. *p='\0';
  93. }
  94. else{
  95. while((ch = getchar()) !='\n' && ch!=EOF);
  96. }
  97. ok = strlen(ptrCliente->direccion);
  98. }while(!ok);
  99.  
  100. do{
  101. mosDtos(ptrCliente);
  102. printf("\n Altura de la calle..: ");
  103. ok = scanf( "%d", &ptrCliente->numCalle ) == 1 && ptrCliente->numCalle >= 1;
  104. while ((ch = getchar()) != EOF && ch != '\n');
  105. }while(!ok);
  106.  
  107. do{
  108. mosDtos(ptrCliente);
  109. printf("\n Ciudad..............: ");
  110. fgets(ptrCliente->ciudad, 30, stdin);
  111. if((p=strchr(ptrCliente->ciudad, '\n'))){
  112. *p='\0';
  113. }
  114. else{
  115. while((ch = getchar()) !='\n' && ch!=EOF);
  116. }
  117. ok = strlen(ptrCliente->ciudad);
  118. }while(!ok);
  119.  
  120. do{
  121. mosDtos(ptrCliente);
  122. printf("\n Provincia...........: ");
  123. fgets(ptrCliente->provincia, 30, stdin);
  124. if((p=strchr(ptrCliente->provincia, '\n'))){
  125. *p='\0';
  126. }
  127. else{
  128. while((ch = getchar()) !='\n' && ch!=EOF);
  129. }
  130. ok = strlen(ptrCliente->provincia);
  131. }while(!ok);
  132. mosDtos(ptrCliente);
  133.  
  134. opciones(ptrCliente);
  135. }
  136.  
  137. void opciones(Cliente *ptrCliente){
  138. int opcion, ok;
  139. char ch;
  140.  
  141. do{
  142. mosDtos(ptrCliente);
  143. printf("\n ========= Opciones =========");
  144. printf("\n 1 - Grabar en disco.");
  145. printf("\n 2 - Introducir nuevamente los datos.");
  146. printf("\n 3 - Finalizar.");
  147.  
  148. printf("\n\n Ingrece opci%cn....: ", 162);
  149. ok = scanf("%d", &opcion) == 1 && opcion >= 1 && opcion <= 3;
  150. while ((ch = getchar()) != EOF && ch != '\n');
  151. }while(!ok);
  152.  
  153. if(opcion == 1){
  154. graDtos(ptrCliente);
  155. }
  156. else if(opcion == 2){
  157. ptrCliente->orden = 0;
  158. strcpy(ptrCliente->nombre, "\0");
  159. strcpy(ptrCliente->apellido, "\0");
  160. strcpy(ptrCliente->direccion, "\0");
  161. ptrCliente->numCalle = 0;
  162. strcpy(ptrCliente->ciudad, "\0");
  163. strcpy(ptrCliente->provincia, "\0");
  164.  
  165. mosDtos(ptrCliente);
  166. ingDtos(ptrCliente);
  167. }
  168.  
  169. }
  170.  
  171. void graDtos(Cliente *ptrCliente){
  172.  
  173. }
  174.  
  175.  

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


Título: Re: Grabar estructura en archivo [lenguaje C] [Windows 7]
Publicado por: ivancea96 en 9 Marzo 2015, 18:58 pm
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.


Título: Re: Grabar estructura en archivo [lenguaje C] [Windows 7]
Publicado por: BloodSharp en 9 Marzo 2015, 20:18 pm
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?

No, para esciribir toda una estructura de una tenés fwrite (https://msdn.microsoft.com/es-ar/library/h9t88zwz.aspx)...


B#


Título: Re: Grabar estructura en archivo [lenguaje C] [Windows 7]
Publicado por: DanielPy en 9 Marzo 2015, 20:43 pm
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


Título: Re: Grabar estructura en archivo [lenguaje C] [Windows 7]
Publicado por: ivancea96 en 9 Marzo 2015, 21:08 pm
Esto mismo respondí en: https://foro.elhacker.net/programacion_cc/vectores_strings_y_archivos_con_clase_c-t431283.0.html (https://foro.elhacker.net/programacion_cc/vectores_strings_y_archivos_con_clase_c-t431283.0.html)


Título: Re: Grabar estructura en archivo [lenguaje C] [Windows 7]
Publicado por: DanielPy en 10 Marzo 2015, 22:28 pm
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


Título: Re: Grabar estructura en archivo [lenguaje C] [Windows 7]
Publicado por: BloodSharp en 11 Marzo 2015, 04:06 am
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

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:

Código
  1. FILE *ptrCte;//Archivo ya abierto
  2. int graDtos(Cliente *ptrCliente)
  3. {
  4.    return fwrite(ptrCliente,sizeof(Cliente),1,ptrCte);
  5. }
  6.  
  7. int leerDatos(Cliente *ptrCliente)
  8. {
  9.    return fread(ptrCliente,sizeof(Cliente),1,ptrCte);
  10. }
  11.  
  12. char *szClave="unaClave";
  13. int graDtosCifrados(Cliente *ptrCliente)
  14. {
  15.    Cliente clienteCifrado;
  16.    memcpy(&clienteCifrado,ptrCliente,sizeof(Cliente));
  17.    //No cifro la estructura original por si la necesito luego
  18.    RutinaParaCifrar(&clienteCifrado,sizeof(Cliente),szClave,strlen(szClave));
  19.    return fwrite(clienteCifrado,sizeof(Cliente),1,ptrCte);
  20. }
  21.  
  22. int leerDatosCifrados(Cliente *ptrCliente)
  23. {
  24.    int bytesleidos;
  25.    Cliente clienteDescifrado;
  26.    byteleidos=fread(clienteDescifrado,sizeof(Cliente),1,ptrCte);
  27.    RutinaParaCifrar(&clienteDescifrado,sizeof(Cliente),szClave,strlen(szClave));
  28.    memcpy(ptrCliente,&clienteDescifrado,sizeof(Cliente));
  29.    return bytesleidos;
  30. }


B#


Título: Re: Grabar estructura en archivo [lenguaje C] [Windows 7]
Publicado por: DanielPy en 13 Marzo 2015, 20:55 pm
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.-       

Código
  1. #include <stdio.h>
  2.  
  3. struct registro{
  4. char nombre[30];
  5. int matricula;
  6. }est;
  7.  
  8. int main(void){
  9. FILE *ptrEst;
  10. int ch;
  11.  
  12. if( (ptrEst = fopen( "ingles.txt" , "a+" )) == NULL ){
  13. printf( "\n\n ERROR, no se pudo abrir el archivo..." );
  14. }
  15. else{
  16. // fread(&est, sizeof(est), 1, ptrEst);
  17. // printf( "\n\n Ultimo ingreso....: %d - %s \n", est.matricula, est.nombre );
  18.  
  19. printf( "\n\n Nombre.........:");
  20. gets(est.nombre);
  21.  
  22. printf( "\n Matricula......:" );
  23. scanf( "%d", &est.matricula );
  24. while ((ch = getchar()) != EOF && ch != '\n');
  25.  
  26. fwrite(&est, sizeof(est), 1, ptrEst);
  27.  
  28. rewind(ptrEst);
  29.  
  30. printf( "\n\n Listado completo\n" );
  31. while( !feof(ptrEst) ){
  32. fread(&est, sizeof(est), 1, ptrEst);
  33. printf( " %d - %s \n", est.matricula, est.nombre );
  34. }
  35.  
  36. fclose(ptrEst);
  37. }
  38.  
  39. return 0;
  40. }
  41.  
Gracias ivancea96 por tú ayuda.-
Saludos.
Daniel


Título: Re: Grabar estructura en archivo [lenguaje C] [Windows 7]
Publicado por: BloodSharp en 13 Marzo 2015, 23:19 pm
Código
  1. //Asumiendo que tenés al menos una entrada de estructura ya previamente guardada...
  2. int ultimaMatricula;
  3. fseek(ptrEst,(-1)*sizeof(int), SEEK_END);
  4. fread(&ultimaMatricula,sizeof(int),1,ptrEst);

Código
  1. printf( "\n\n Listado completo\n" );
  2. fread(&est, sizeof(est), 1, ptrEst);
  3. while( !feof(ptrEst) )
  4. printf( " %d - %s \n", est.matricula, est.nombre ),
  5. fread(&est, sizeof(est), 1, ptrEst);
  6.  


B#


Título: Re: Grabar estructura en archivo [lenguaje C] [Windows 7]
Publicado por: DanielPy en 14 Marzo 2015, 02:27 am
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   


Título: Re: Grabar estructura en archivo [lenguaje C] [Windows 7]
Publicado por: rir3760 en 14 Marzo 2015, 03:34 am
Lo último es un inconveniente con el bucle while, siempre me duplica el último dato.
El problema se debe a que estas utilizando feof para controlar el bucle de lectura y con ello se realiza una iteración de mas:
Código
  1. printf( "\n\n Listado completo\n" );
  2. while( !feof(ptrEst) ){
  3.   fread(&est, sizeof(est), 1, ptrEst);
  4.   printf( " %d - %s \n", est.matricula, est.nombre );
  5. }
La solución manteniendo el uso de la función feof ya te la dio BloodSharp, solo ten cuidado con el bucle ya que son dos expresiones separadas por el operador condicional ",".

Otra opción consiste en olvidarse de feof, temas relacionados con ello los puedes consultar mediante el motor de búsqueda de los foros, lo usual salvo casos excepcionales es, en lugar del uso de la bendita función, utilizar el valor de retorno de la función en turno. En tu caso basta con:
Código
  1. puts("Listado completo:");
  2. while (fread(&est, sizeof est, 1, ptrEst) == 1)
  3.   printf(" %d - %s \n", est.matricula, est.nombre);

Un saludo


Título: Re: Grabar estructura en archivo [lenguaje C] [Windows 7]
Publicado por: DanielPy en 14 Marzo 2015, 04:00 am
Hola rir3760.
Ahora si funciona correctamente, sólo que la primer parte quedo de esta manera (lo copié de este foro).-

Código
  1. ......................
  2. ......................
  3. long tam;
  4. ......................
  5. ......................
  6. tam=sizeof(struct registro);
  7. fseek(ptrEst, 0, SEEK_END);
  8. ultimaMatricula=ftell(ptrEst)/tam;
  9. est.matricula = ultimaMatricula+1;
  10.  
  11. printf( "\n Matricula......: %d",  est.matricula);
  12.  
Sólo una cosita más, me podrías decir el significado de == 1, debo interpretar que si es cero termina el bucle, no se.-

Saludos.
Daniel


Título: Re: Grabar estructura en archivo [lenguaje C] [Windows 7]
Publicado por: rir3760 en 14 Marzo 2015, 04:25 am
Sólo una cosita más, me podrías decir el significado de == 1, debo interpretar que si es cero termina el bucle
Correcto. La función fread retorna el numero de elementos leídos con éxito y este valor sera igual o menor al tercer argumento de la función (en tu caso y en resumen 1 ==> lectura exitosa, 0 ==> error o fin de archivo).

Un saludo