Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: diegoCmC en 11 Septiembre 2012, 17:09 pm



Título: Usos fwrite, fread
Publicado por: diegoCmC en 11 Septiembre 2012, 17:09 pm
Hola a todos, estoy siguiendo un manual de programación, y ando con el manejo de ficheros, el problema es que me mandan mejorar un programa que ya he creado y no entiendo las mejoras.

En el programa leo los datos del fichero con fgets y fscanf para almacenarlos en el struct, y me mandan leerlos mediante fread y escribirlos con fwrite en lugar de con fprintf, pero no entiendo porque mejora eso el programa

A ver si alguien me orienta un poco, pongo el código que tengo hasta ahora, aunque no quiero que nadie implemente el uso de fwrite y fread, solo quiero una explicación

Un saludo


Código
  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. struct fecha{
  5.    int dia, mes, año;
  6. };
  7.  
  8. struct{
  9.    char nombre[21], direccion[41], email[41];
  10.    int telefono;
  11.    struct fecha nacimiento;
  12. }agenda[100];
  13.  
  14. int main(){
  15.    int opcion;//Almacena la opcion elegida en el menu
  16.    int i=0;//Contador del stuct para saber los datos leidos y escritos
  17.    int j,k; //Variables auxiliares para los bucles
  18.    int tipo_busqueda;
  19.    char cadena_temporal[9], nombre_buscar[20]; //Cadenas auxiliares para leer numeros con gets()
  20.    FILE* fichero;
  21.  
  22.    //Leemos los datos existentes
  23.    fichero=fopen("agenda.dat", "rt");
  24.  
  25.    if(fichero==NULL){//Si no existe el fichero damos aviso de que lo vamos a crear
  26.        printf("El fichero aun no existe, asi que se creara\n\n");
  27.    }
  28.    else{
  29.        printf("Lectura correcta del fichero\n\n");
  30.        while(! feof(fichero)){//Leemos los datos del fichero y los almacenamos en el struct
  31.            fgetc(fichero);
  32.            fgets(agenda[i].nombre,20,fichero);
  33.            //Quitamos los espacios que hay antes de la cadena
  34.            for(k=0; k<21;k++){
  35.                if(agenda[i].nombre[k]!=' '){
  36.                    j=0;
  37.                    for(;k<21;k++){
  38.                        agenda[i].nombre[j]=agenda[i].nombre[k];
  39.                        j++;
  40.                    }
  41.                }
  42.            }
  43.            fgetc(fichero);
  44.            fgets(agenda[i].direccion,40,fichero);
  45.            //Quitamos los espacios que hay antes de la cadena
  46.            for(k=0; k<41;k++){
  47.                if(agenda[i].direccion[k]!=' '){
  48.                    j=0;
  49.                    for(;k<41;k++){
  50.                        agenda[i].direccion[j]=agenda[i].direccion[k];
  51.                        j++;
  52.                    }
  53.                }
  54.            }
  55.            fscanf(fichero,"%9d", &agenda[i].telefono);
  56.            fgetc(fichero);
  57.            fgets(agenda[i].email,40,fichero);
  58.            //Quitamos los espacios que hay antes de la cadena
  59.            for(k=0; k<41;k++){
  60.                if(agenda[i].email[k]!=' '){
  61.                    j=0;
  62.                    for(;k<41;k++){
  63.                        agenda[i].email[j]=agenda[i].email[k];
  64.                        j++;
  65.                    }
  66.                }
  67.            }
  68.            fscanf(fichero,"%d%d%d", &agenda[i].nacimiento.dia, &agenda[i].nacimiento.mes,
  69.                   &agenda[i].nacimiento.año);
  70.            fgetc(fichero);
  71.            i++;
  72.        }
  73.    }
  74.  
  75.  
  76.    fclose(fichero);
  77.  
  78.  
  79.    //Interactuamos con el usuario
  80.    do{
  81.        //Imprimimos el menu de opciones
  82.        printf("1. Anadir nuevo dato\n");
  83.        printf("2. Visualizar los nombres registrados\n");
  84.        printf("3. Mostrar todos los datos de alguien\n");
  85.        printf("4. Salir\n");
  86.        printf("Opcion: ");
  87.        gets(cadena_temporal);
  88.        sscanf(cadena_temporal,"%1d", &opcion);
  89.        printf("\n");
  90.  
  91.        if(opcion==1 && i>99){//Si la agenda esta llena no tomara mas datos
  92.            printf("La agenda ya esta llena\n\n");
  93.  
  94.        }
  95.        else{//Cuando la agenda no esta llena aun
  96.  
  97.            //Creamos un switch con las opciones
  98.            switch(opcion){
  99.                case 1://Añadimos un nuevo dato al struct
  100.                    printf("Introduce el nombre: ");
  101.                    gets(agenda[i].nombre);
  102.                    printf("Introduce la direccion: ");
  103.                    gets(agenda[i].direccion);
  104.                    printf("Introduce el telefono: ");
  105.                    gets(cadena_temporal);
  106.                    sscanf(cadena_temporal,"%9d", &agenda[i].telefono);
  107.                    printf("Introduce el e-mail: ");
  108.                    gets(agenda[i].email);
  109.                    printf("Introduce la fecha de nacimiento\n");
  110.                    printf("\tdia: ");
  111.                    gets(cadena_temporal);
  112.                    sscanf(cadena_temporal,"%2d", &agenda[i].nacimiento.dia);
  113.                    printf("\tmes: ");
  114.                    gets(cadena_temporal);
  115.                    sscanf(cadena_temporal, "%2d", &agenda[i].nacimiento.mes);
  116.                    printf("\tanio: ");
  117.                    gets(cadena_temporal);
  118.                    sscanf(cadena_temporal, "%4d", &agenda[i].nacimiento.año);
  119.                    i++;
  120.                    break;
  121.                case 2://Mostrar por pantalla los nombres registrados
  122.                    for(j=0; j<i; j++){
  123.                        puts(agenda[j].nombre);
  124.                    }
  125.                    printf("\n");
  126.                    break;
  127.                case 3://Mostrar todos los datos de alguna persona
  128.  
  129.                    do{//Busqueda parcial o busqueda completa
  130.                        printf("Busqueda completa(0) o busqueda parcial(1): ");
  131.                        gets(cadena_temporal);
  132.                        sscanf(cadena_temporal, "%1d", &tipo_busqueda);
  133.                        if(tipo_busqueda!=0 && tipo_busqueda!=1)
  134.                            printf("La opcion introducida no es correcta\n");
  135.                    }while(tipo_busqueda!=0 && tipo_busqueda!=1);
  136.  
  137.                    printf("Nombre a buscar: ");
  138.                    gets(nombre_buscar);
  139.                    printf("\n");
  140.  
  141.                    switch(tipo_busqueda){
  142.                        case 0://Busqueda completa
  143.                            for(j=0; j<i; j++){
  144.                                if(strcmp(nombre_buscar,agenda[j].nombre)==0){
  145.                                    printf("Nombre: %s, direccion: %s, Telefono %d\ne-mail: %s, Fecha nacimiento: %d/%d/%d\n\n",
  146.                                        agenda[j].nombre, agenda[j].direccion, agenda[j].telefono, agenda[j].email,
  147.                                        agenda[j].nacimiento.dia, agenda[j].nacimiento.mes, agenda[j].nacimiento.año);
  148.                                }
  149.  
  150.                            }
  151.                            break;
  152.                        case 1://Busqueda parcial
  153.                            for(j=0; j<i; j++){
  154.                                if(strstr(agenda[j].nombre,nombre_buscar)!=NULL){
  155.                                    printf("Nombre: %s, direccion: %s, Telefono %d\ne-mail: %s, Fecha nacimiento: %d/%d/%d\n\n",
  156.                                        agenda[j].nombre, agenda[j].direccion, agenda[j].telefono, agenda[j].email,
  157.                                        agenda[j].nacimiento.dia, agenda[j].nacimiento.mes, agenda[j].nacimiento.año);
  158.                                }
  159.                            }
  160.                            break;
  161.                        default:;
  162.                    }
  163.                    break;
  164.                case 4://Opcion de salir
  165.                    break;
  166.                default: printf("La opcion elegida no es correcta\n");
  167.            }
  168.        }
  169.        printf("\n");
  170.  
  171.  
  172.    }while(opcion!=4);
  173.  
  174.  
  175.    //Guardamos los datos existentes en el fichero de agenda
  176.    fichero=fopen("agenda.dat", "wt");
  177.    for(j=0; j<i; j++){
  178.        if(j!=i-1){
  179.            fprintf(fichero, "%20s%40s%9d%40s%2d %2d %4d\n", agenda[j].nombre, agenda[j].direccion, agenda[j].telefono,
  180.                    agenda[j].email, agenda[j].nacimiento.dia, agenda[j].nacimiento.mes, agenda[j].nacimiento.año);
  181.        }
  182.        else
  183.            fprintf(fichero, "%20s%40s%9d%40s%2d %2d %4d", agenda[j].nombre, agenda[j].direccion, agenda[j].telefono,
  184.                    agenda[j].email, agenda[j].nacimiento.dia, agenda[j].nacimiento.mes, agenda[j].nacimiento.año);
  185.    }
  186.  
  187.    fclose(fichero);
  188.  
  189.    return 0;
  190. }
  191.  


Título: Re: Usos fwrite, fread
Publicado por: tremolero en 11 Septiembre 2012, 23:48 pm
Hola diegoCmC, yo la verdad esque no tengo ni dea, pero si el ingles no es un problema para ti, tal vez mirando las descripcion de las 2 puedas ver la diferencia:

fwrite - http://www.cplusplus.com/reference/clibrary/cstdio/fwrite/ (http://www.cplusplus.com/reference/clibrary/cstdio/fwrite/)
fprintf - http://www.cplusplus.com/reference/clibrary/cstdio/fprintf/ (http://www.cplusplus.com/reference/clibrary/cstdio/fprintf/)

Y para colmo tambien he visto esto xD espero que te ayude

http://hegdesuhas.wordpress.com/2011/02/28/fprintf-vs-fwrite/ (http://hegdesuhas.wordpress.com/2011/02/28/fprintf-vs-fwrite/)

Se supone que explican la diferencia entre los 2, creo que es el tamaño al guardar y el tema de seguridad creo... bueno ahi te lo dejo.

Saludos...


Título: Re: Usos fwrite, fread
Publicado por: DickGumshoe en 12 Septiembre 2012, 01:55 am
La diferencia es que, si tienes un vector de n elementos, con fprintf tendrías que recorrerlo con un bucle, sin embargo con fwrite indicas el número de elementos a poner en el fichero y listo, ya están guardados. Lo mismo con fread respecto a fscanf.

Ejemplo:

Código
  1.  
  2. #include <stdio.h>
  3.  
  4. int main()
  5. {
  6.  
  7. int V[13] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
  8. int i;
  9. int datos[13];
  10. FILE *fp;
  11.  
  12. fp = fopen("fichero.txt", "w+");
  13. for(i=0;i<13;i++) fprintf(fp, "%d ", V[i]); //Ponemos en fichero
  14. rewind(fp); //Situamos el cursor al principio del fichero
  15. for(i=0;i<13;i++) fscanf(fp, "%d", &datos[i]); //Leemos los datos del fichero
  16. fclose(fp);
  17. for(i=0;i<13;i++) printf("%d    ", datos[i]); //Imprimimos los datos
  18. return 0;
  19.  
  20. }
  21.  

Código
  1. #include <stdio.h>
  2.  
  3. int main()
  4. {
  5.  
  6. int V[13] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
  7. int i;
  8. int datos[13];
  9. FILE *fp;
  10.  
  11. fp = fopen("fichero.txt", "w+");
  12. fwrite(V, sizeof(int), 13, fp);  //Ponemos en fichero
  13. rewind(fp); //Situamos el cursor al principio del fichero
  14. fread(datos, sizeof(int), 13, fp); //Leemos los datos del fichero
  15. fclose(fp);
  16. for(i=0;i<13;i++) printf("%d    ", datos[i]); //Imprimimos los datos
  17. return 0;
  18.  
  19. }
  20.  

Además, como bien ha dicho el compañero Tremolero, es por seguridad. Intenta meter los datos con fwrite en un fichero *.txt, y verás que no entiendes lo que pone. Pero, sin embargo, al leerlo con fread, sí entenderás su contenido.

Un saludo.


Título: Re: Usos fwrite, fread
Publicado por: durasno en 12 Septiembre 2012, 22:42 pm
Hola! no le encuentro sentido al tema de seguridad(nunca lei algo sobre eso), me parece que la ventaja pasa mas por la velocidad al acceder a los datos ya que se trabaja con flujos binarios y el echo de que no se pueda visualizar en un archivo es porque fwrite no le da formato a su salida.
La otra ventaja seria la cantidad de lineas de codigo que te ahorras; como ves en el ejemplo de DickGumshoe solo uso una linea para guardar un arreglo y si aplicas fwrite y fread en tu codigo(diegoCmC) vas a ver q el programa se acorta bastante


Saludos


PD: por que pones fgetc antes de los fgets?? para que es??


Título: Re: Usos fwrite, fread
Publicado por: diegoCmC en 13 Septiembre 2012, 21:42 pm
Ponia el fgetc por las dimensiones de la cadena, ya que si guardaba todos los valores se me iba de rango, ya que no dejaba hueco para el \0 que cierra la cadena. La verdad que si se me acorto bastante el codigo. Gracias a todos por las respuestas

Código
  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. struct fecha{//Estructura que almacena una fecha en dia, mes año
  5.    int dia, mes, año;
  6. };
  7.  
  8. struct datos{//Estructura que almacena todos los datos
  9.    char nombre[21], direccion[41], email[41];
  10.    int telefono;
  11.    struct fecha nacimiento;
  12. }agenda[100];//Limite de 100, cambiar el numero para ampliarlo
  13.  
  14. void imprimir_menu(void);
  15. int seleccionar_opcion(void);
  16.  
  17. int main(){
  18.    int opcion;//Almacena la opcion elegida en el menu
  19.    int i=0;//Contador del stuct para saber los datos leidos y escritos
  20.    int j,k; //Variables auxiliares para los bucles
  21.    int tipo_busqueda;
  22.    char cadena_temporal[9], nombre_buscar[20]; //Cadenas auxiliares para leer numeros con gets()
  23.    FILE* fichero;
  24.  
  25.    //Leemos los datos existentes
  26.    fichero=fopen("agenda.dat", "rb");
  27.  
  28.    if(fichero==NULL){//Si no existe el fichero damos aviso de que lo vamos a crear
  29.        printf("El fichero aun no existe, asi que se creara\n\n");
  30.    }
  31.    else{
  32.        printf("Lectura correcta del fichero\n\n");
  33.        while(! feof(fichero)){//Leemos los datos del fichero y los almacenamos en el struct
  34.            fread(&agenda[i],1,sizeof(struct datos),fichero);
  35.            i++;
  36.        }
  37.    }
  38.  
  39.  
  40.    fclose(fichero);
  41.  
  42.  
  43.    //Interactuamos con el usuario
  44.    do{
  45.  
  46.    imprimir_menu();
  47.    opcion=seleccionar_opcion();
  48.  
  49.        if(opcion==1 && i>99){//Si la agenda esta llena no tomara mas datos
  50.            printf("La agenda ya esta llena\n\n");
  51.  
  52.        }
  53.        else{//Cuando la agenda no esta llena aun
  54.  
  55.            //Creamos un switch con las opciones
  56.            switch(opcion){
  57.                case 1://Añadimos un nuevo dato al struct
  58.                    printf("Introduce el nombre: ");
  59.                    gets(agenda[i].nombre);
  60.                    printf("Introduce la direccion: ");
  61.                    gets(agenda[i].direccion);
  62.                    printf("Introduce el telefono: ");
  63.                    gets(cadena_temporal);
  64.                    sscanf(cadena_temporal,"%9d", &agenda[i].telefono);
  65.                    printf("Introduce el e-mail: ");
  66.                    gets(agenda[i].email);
  67.                    printf("Introduce la fecha de nacimiento\n");
  68.                    printf("\tdia: ");
  69.                    gets(cadena_temporal);
  70.                    sscanf(cadena_temporal,"%2d", &agenda[i].nacimiento.dia);
  71.                    printf("\tmes: ");
  72.                    gets(cadena_temporal);
  73.                    sscanf(cadena_temporal, "%2d", &agenda[i].nacimiento.mes);
  74.                    printf("\tanio: ");
  75.                    gets(cadena_temporal);
  76.                    sscanf(cadena_temporal, "%4d", &agenda[i].nacimiento.año);
  77.                    i++;
  78.                    break;
  79.                case 2://Mostrar por pantalla los nombres registrados
  80.                    for(j=0; j<i; j++){
  81.                        puts(agenda[j].nombre);
  82.                    }
  83.                    printf("\n");
  84.                    break;
  85.                case 3://Mostrar todos los datos de alguna persona
  86.  
  87.                    do{//Busqueda parcial o busqueda completa
  88.                        printf("Busqueda completa(0) o busqueda parcial(1): ");
  89.                        gets(cadena_temporal);
  90.                        sscanf(cadena_temporal, "%1d", &tipo_busqueda);
  91.                        if(tipo_busqueda!=0 && tipo_busqueda!=1)
  92.                            printf("La opcion introducida no es correcta\n");
  93.                    }while(tipo_busqueda!=0 && tipo_busqueda!=1);
  94.  
  95.                    printf("Nombre a buscar: ");
  96.                    gets(nombre_buscar);
  97.                    printf("\n");
  98.  
  99.                    switch(tipo_busqueda){
  100.                        case 0://Busqueda completa
  101.                            for(j=0; j<i; j++){
  102.                                if(strcmp(nombre_buscar,agenda[j].nombre)==0){
  103.                                    printf("Nombre: %s, direccion: %s, Telefono %d\ne-mail: %s, Fecha nacimiento: %d/%d/%d\n\n",
  104.                                        agenda[j].nombre, agenda[j].direccion, agenda[j].telefono, agenda[j].email,
  105.                                        agenda[j].nacimiento.dia, agenda[j].nacimiento.mes, agenda[j].nacimiento.año);
  106.                                }
  107.  
  108.                            }
  109.                            break;
  110.                        case 1://Busqueda parcial
  111.                            for(j=0; j<i; j++){
  112.                                if(strstr(agenda[j].nombre,nombre_buscar)!=NULL){
  113.                                    printf("Nombre: %s, direccion: %s, Telefono %d\ne-mail: %s, Fecha nacimiento: %d/%d/%d\n\n",
  114.                                        agenda[j].nombre, agenda[j].direccion, agenda[j].telefono, agenda[j].email,
  115.                                        agenda[j].nacimiento.dia, agenda[j].nacimiento.mes, agenda[j].nacimiento.año);
  116.                                }
  117.                            }
  118.                            break;
  119.                        default:;
  120.                    }
  121.                    break;
  122.                case 4://Opcion de salir
  123.                    break;
  124.                default: printf("La opcion elegida no es correcta\n");
  125.            }
  126.        }
  127.        printf("\n");
  128.  
  129.  
  130.    }while(opcion!=4);
  131.  
  132.  
  133.    //Guardamos los datos existentes en el fichero de agenda
  134.    fichero=fopen("agenda.dat", "wb");
  135.    for(j=0; j<i-1; j++){
  136.        fwrite(&agenda[j],sizeof(struct datos),1,fichero);
  137.    }
  138.  
  139.    fclose(fichero);
  140.  
  141.    return 0;
  142. }
  143.  
  144. void imprimir_menu(void){
  145.    //Imprimimos el menu de opciones
  146.    printf("1. Anadir nuevo dato\n");
  147.    printf("2. Visualizar los nombres registrados\n");
  148.    printf("3. Mostrar todos los datos de alguien\n");
  149.    printf("4. Salir\n");
  150. }
  151.  
  152. int seleccionar_opcion(void){
  153.    int opcion;
  154.    char cadena_temporal[2];
  155.  
  156.    printf("Opcion: ");
  157.    gets(cadena_temporal);
  158.    sscanf(cadena_temporal,"%1d", &opcion);
  159.  
  160.    if(opcion!=1 && opcion!=2 && opcion!=3 && opcion!=4){
  161.        printf("La opcion elegida no es correcta\n\n");
  162.        seleccionar_opcion();
  163.    }
  164.  
  165.    printf("\n");
  166.    return opcion;
  167. }
  168.