[ Foro de C ]

Problema con fread()

21-Jun-2011 20:18
carlosg solaris
4 Respuestas

Saludos al foro, tengo un problema al ejecutar el presente codigo. El programa Graba una matriz de enteros en un archivo y despues lo lee del mismo archivo y lo muestra en pantalla, la grabación es OK, pero la lectura con fread() solo me muestra la mitad de los elementos de la matriz.  

ret = fread(&matriz, object_size, object_count, flujo);

fread me devuelve el numero de objetos grabados (lo recupero en ret); Este valor debe a su vez debe coincidir con object_count.

matriz grabada     matriz leida
2 4 6 8 10         2 4 6 8 10
12 14 16 18 20     12 14 16 18 20
22 24 26 28 30     22 24 0 0 0
32 34 36 38 40     0 0 0 0 0
42 44 46 48 50     0 0 0 0 0

Detalles Sistema
SO: Windows XP,  Compilador: gcc 4.5.2 (MinGW)

int main(){
int fila, col, lfallo;
FILE *flujo;
int close_error;
char archivo[]="numbers.dat";

size_t object_size = sizeof(int);
size_t object_count = 25;
size_t ret;
     
int matriz[5][5]={2,4,6,8,10,
             12,14,16,18,20,
             22,24,26,28,30,
             32,34,36,38,40,
             42,44,46,48,50
};

printf("Valores iniciales de la matriz\n");
for(fila=0; fila <=4; fila++){
for(col=0;col<=4; col++)
printf("%d ",matriz[fila][col]);
printf("\n");
}

flujo = fopen(archivo, "w");
ret = fwrite(&matriz, object_size, object_count, flujo);
if (ret != object_count)
printf("Error al excribir datos al archivo\n");
else
printf("Datos escritos al archivo satisfactoriamente\n");
 fflush(flujo);
close_error = fclose(flujo);
if (close_error!=0)
printf("No se puedo cerrar el archivo '%s'\n", archivo);
else
printf("archivo '%s' cerrado\n", archivo);
 printf("===========================================\n");

 /*VACIAMOS EL ARCHIVO*/
printf("Zeroing matriz...\n");
for (fila = 0; fila <= 4; fila++){
for(col=0; col <= 4; col++){
matriz[fila][col]=0;
printf("%d ", matriz[fila][col]);
}
printf("\n");
}

 printf("===========================================\n");
 /*LEEMOS EL ARCHIVO*/
printf("Ahora leeremos datos almacenados del archivo..!\n\n");
flujo = fopen(archivo, "r");
if (flujo==NULL)
   printf("No se pudo abrir archivo '%s'\n", archivo);
 else
   printf("Archivo '%s' abierto ..!\n", archivo);

ret = fread(&matriz, object_size, object_count, flujo);
 lfallo= (ret != object_count);
if (lfallo)
printf("Error leyendo data desde archivo...!\n");
else
printf("Leyendo datos del archivo satisfactoriamente\n");

for (fila =0; fila<=4 ; fila++){
for (col=0; col>=4; col++)
printf("%d ", matriz[fila][col]);
printf("\n");
}
fclose(flujo);

return 0;
}

Referencia. ejemplo tomado del libro "GNU C Programming Tutorial" (pag 114).


21-Jun-2011 23:11
Nacho Cabanes (+84)

Es que estás mezclando dos formas distintas de acceder a fichero:

- Si quieres escribir con "fprintf", lo razonable es que leas con "fscanf".

- Si quieres leer con "fread", deberías escribir con "fwrite".

Escoge una de esas dos formas de trabajar, y aplícala en las dos partes del programa (cargar y guardar).


21-Jun-2011 23:45
carlosg solaris

Me parece que te has confundido, si miras bien el codigo estoy usando fwrite() y fread() para escribir y leer una matriz.
No he usado fprintf en ningún lado, solo he usado printf para mostrar mensajes y los datos en la pantalla. como depuracion, no para escribir en el archivo.

De todas formas gracias por tu atención.


22-Jun-2011 04:21
carlosg solaris

PROBLEMA SOLUCIONADO:
Resulta que bajo windows hay 2 modos de abrir los archivos, en modo binario y en modo texto.

En modo texto la secuencia 0A en este caso se traduce erroneamente como el fin de una linea, entonces al leer/escribir divide el contenido en lineas, y por eso trunca el contenido. De hecho, el tamaño de tu archivo era de 101 bytes y no 100 bytes (25x4) como debia ser, ya que convertia el 0A en 0D 0A al escribir. En windows cada linea lleva un retorno de carro / avance de linea, en linux solo existe el avance de linea 0A, y todos los archivos se manejan como si fueran binarios.

Si no especificas el modo, los archivos se abren por defecto en modo texto.

La solucion es especificar explicitamente que vamos a abrir el archivo en modo binario, de esa forma se elimina el problema.

Se debe cambiar las siguientes lineas:
Cambiar--> flujo = fopen(archivo, "w");
por ---> flujo = fopen(archivo, "wb");
y
Cambiar--> flujo = fopen(archivo, "r");
por ---> flujo = fopen(archivo, "rb");

No es un problema sencillo de resolver, pero es una solución muy importante a tener en cuenta.
:)


22-Jun-2011 10:48
Nacho Cabanes (+84)

Efectivamente, ese es el problema. Hay tantos "printf" que en un primer vistazo me había parecido que volcabas los datos con printf, pero no es así, sino que el modo de apertura es incorrecto.

Pero lo que que haya dos modos de abrir archivos no es bajo Windows, sino en cualquier compilador de C.

Conceptualmente, si el fichero es binario (vas a leer con "fread" y escribir con "fwrite"), deberías abrirlo con "rb" o "wb", según el caso, pero no sólo porque trabajas en Windows, sino porque se supone que pretendes manejar un fichero binario.  ;-)

Eso sí, es fácil que el problema se agrave con Windows, que convierte los avances de línea \n en dos caracteres, con lo que el fichero (si contiene caracteres de avance de línea) se descuadre.

Pero insisto: oblígate a usar "rt" o "rb" según el caso, en vez de "r" como modo de apertura (mira el apartado 6 del curso):

http://www.aprendeaprogramar.com/mod/forum/discuss.php?d=530








(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.)