[ Foro de C ]

Problema con ficheros y fread

10-Aug-2010 00:40
javi asdl asdnpwnd
7 Respuestas

Hola!! Antes que nada, os dejo el codigo:

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

main(){
struct{
char nombre[50];
char direccion[100];
char movil[10];
char email[100];
short int nDia;
short int nMes;
short int nAno;
}persona;
int i;
int opcion=1; //Opcion elegida por le usuario
char textoTemporal[40];
FILE *fichero;

while(opcion != 0){
printf("1.- A%cadir ficha nueva\n\n",164);
printf("2.- Visualizar nombres de fichas existentes\n\n");
printf("3.- Buscar por nombre\n\n");
printf("Teclee su opcion: ");
gets(textoTemporal);
sscanf(textoTemporal,"%d",&opcion);

switch(opcion){
case 1:
fichero=fopen("gente.dat","ab");
printf("Nombre: ");
gets(persona.nombre);
printf("Direccion: ");
gets(persona.direccion);
printf("Telefono movil: ");
gets(persona.movil);
printf("Email: ");
gets(persona.email);
printf("Dia de nacimiento: ");
gets(textoTemporal);
sscanf(textoTemporal,"%d",&persona.nDia);
printf("Mes de nacimiento: ");
gets(textoTemporal);
sscanf(textoTemporal,"%d",&persona.nMes);
printf("Año de nacimiento: ");
gets(textoTemporal);
sscanf(textoTemporal,"%d",&persona.nAno);
fwrite(&persona,1,sizeof(persona),fichero);
fclose(fichero);
system("cls");
break;
case 2:
fichero=fopen("gente.dat","rb");
while(feof(fichero) == 0){
fread(&persona,1,sizeof(persona),fichero);
puts(persona.nombre);
}
fclose(fichero);
break;

case 3:
printf("Introduzca el nombre de la persona: ");
gets(textoTemporal);
fichero=fopen("gente.dat","rb");
fread(persona.nombre,1,sizeof(persona.nombre),fichero);
fread(persona.direccion,1,sizeof(persona.direccion),fichero);
fread(persona.movil,1,sizeof(persona.movil),fichero);
fread(persona.email,1,sizeof(persona.email),fichero);
fread(&persona.nDia,sizeof(persona.nDia),1,fichero);
fread(&persona.nMes,sizeof(persona.nMes),1,fichero);
fread(&persona.nAno,sizeof(persona.nAno),1,fichero);
if((strcmp(persona.nombre,textoTemporal)== 0)){
printf("Nombre: ");
puts(persona.nombre);
printf("Direccion: ");
puts(persona.direccion);
printf("Movil: ");
puts(persona.movil);
printf("email: \n");
puts(persona.email);
printf("Dia de nacimiento: %d\n",persona.nDia);
printf("Mes de nacimiento: %d\n",persona.nMes);
printf("A%co de nacimiento: %d\n",164,persona.nAno);
}
fclose(fichero);
}
}
}

El problema es que, cuando escojo la opcion 2, se me muestran los nombres, pero el ultimo siempre se repite dos veces. He visto el archivo, y el programa guarda los datos en dos lineas distintas y no se cual es la razon. A ver si me podeis ayudar.
Gracias!!


10-Aug-2010 12:07
Nacho Cabanes (+31)

Claro. No estás comprobando el valor que devuelve "fread", sino que estás dando por sentado que la lectura ha sido correcta. Ten en cuenta que "feof" se activa cuando ya no has podido leer, pero no cuando te paras al final, de modo que tú haces una nueva lectura más allá del final del fichero, de la que no obtienes datos, pero no te das cuenta porque no compruebas el valor que te devuelve "fread".

Mira el apartado 6.7 del curso en

http://www.aprendeaprogramar.com/mod/resource/view.php?id=322


10-Aug-2010 13:55
javi asdl asdnpwnd

Gracias, ya esta solucionado. He comprobado con un if el fread, y si es igual a 0, break para que salga del while.

fichero=fopen("gente.dat","rb");
while(!feof(fichero)){
resultado=fread(&persona,sizeof(persona),1,fichero);
if(resultado == 0){
break;
}
puts(persona.nombre);
}
fclose(fichero);
break;


11-Aug-2010 00:13
emuletas yp

Personalmente, yo lo haría así:

if(resultado == 0) break;

Creo que es mas cómodo y legible.


11-Aug-2010 01:13
Nacho Cabanes (+31)

Yo prefiero evitar los "break" si no son realmente imprescindibles, para que no haya que "bucear" en el código para encontrar cual es el bloque que está interrumpiendo, así que yo haría algo como

fichero=fopen("gente.dat","rb");
while(!feof(fichero)){
 resultado=fread(&persona,sizeof(persona),1,fichero);
 if(resultado == sizeof(persona)){
   puts(persona.nombre);
 }
}
fclose(fichero);


o bien dejando la condición de salida al final:


fichero=fopen("gente.dat","rb");
do
{
 resultado=fread(&persona,sizeof(persona),1,fichero);
 if(resultado == sizeof(persona)){
   puts(persona.nombre);
 }
}
while(!feof(fichero))
fclose(fichero);


15-May-2012 17:24
Antonio Rodriguez

Hola!

Ante todo me presento: He intentado varias veces aprender un lenguaje de programación, pero ya sea porque el curso no me enganchaba, no elegía el lenguaje correcto u otros motivos al final terminaba por dejarlo.
Finalmente he encontrado el curso de C de Nacho Cabanes y es el curso en el que más lejos he llegado, estoy aprendiendo mucho y sigo interesado, así que cuenta con muchas posibilidades de ser el primer curso que finalice  ^-)

Actualmente estoy con el tema 6, pero me he tropezado con las funciones fread y fwrite y me está costando seguir adelante.

Tomemos el fuente de Javi, en su apartado 2 que es el que le estaba dando problemas:

case 2:
fichero=fopen("gente.dat","rb");
while(feof(fichero) == 0){
fread(&persona,1,sizeof(persona),fichero);
puts(persona.nombre);
}
fclose(fichero);
break;

Yo interpreto la función fread de la siguiente forma:

"vamos a leer de un fichero llamado "fichero" un numero de datos que viene determinado por el tamaño del struct "persona", cada uno de tamaño 1 y lo vamos a almacenar en el struct "persona""

Posiblemente esta lectura sea errónea, pero la cosa se complica más al ver la corrección propuesta por Nacho:

fichero=fopen("gente.dat","rb");
do
{
  resultado=fread(&persona,sizeof(persona),1,fichero);
  if(resultado == sizeof(persona)){
    puts(persona.nombre);
  }
}
while(!feof(fichero))
fclose(fichero);

donde se intercambian el número de datos a leer (1 en este caso) y el tamaño de esos datos (determinado por el tamaño del struct "persona")

¿cual es la opción correcta? ¿son ambas válidas? ¿estoy "leyendo" la función fread de forma correcta? De ser así, ¿podrías explicar más detalladamente cómo habría que leer las funciones fread y fwrite?

Muchas gracias por adelantado!


15-May-2012 23:47
Nacho Cabanes (+31)

Bienvenido, Antonio.

Ambas opciones son válidas. Imagina que es "struct persona" tiene de tamaño 10 bytes. No hay una gran diferencia entre decir "lee 10 datos de 1 byte" o "lee un bloque de 10 bytes".

En teoría, la definición de "fread" espera que el primero de esos dos datos sea el tamaño de cada bloque y el segundo sea la cantidad de bloques a leer. Por eso yo usé el otro formato. Pero insisto: el resultado sería el mismo:

 
size_t fread(void *datos, size_t tamaño, size_t cantidad, FILE *fichero);
 



como puedes ver aquí:

http://www.nachocabanes.com/c/referencia/detalle.php?funcion=fread


16-May-2012 00:09
Antonio Rodriguez

Muchas gracias por la pronta respuesta Nacho, ya me ha quedado más clara la función :)






(No se puede continuar esta discusión porque tiene más de dos meses de antigüedad. Si tienes dudas parecidas, abre un nuevo hilo.)