En C puedes realizar las operaciones de lectura y escritura de varias maneras:
Leer y escribir carácter a carácter (o lo que es lo mismo,
byte a byte), con funciones como
fgetc
y fputc
.
Leer y escribir línea a línea, con funciones como
fgets
y fputs
.
Leer y escribir un bloque de caracteres (o bytes) cada vez,
con fread
y fwrite
.
Para este curso nos vamos a centrar en la última, la lectura por bloques, que nos será útil tanto para ficheros de texto como para binarios.
En C contamos con las funciones fread
y
fwrite
para realizar operaciones E/S por bloques.
La sintaxis de fread
es la siguiente:
#include <stdio.h> size_t fread(void *ptr, size_t size, size_t n, FILE *stream);
Aquí ptr
es un array donde se van a almacenar
los datos que se van a leer.
size
indica el tamaño de cada elemento del array.
n
especifica el número de elementos que se van a leer.
stream
es un puntero a un fichero que ha tenido que haber
sido abierto previamente.
size_t
es un tipo que está definido también en la cabecera
stdio.h
.
La función devuelve el número de elementos que realmente se han leído
(que puede ser menor que n
); si
todo ha ido bien o aún no se ha llegado al final del fichero, ese
número devuelto debería ser mayor que 0 e igual o menor (en caso de que
no sepamos la longitud de lo que vamos a leer) que el tercer argumento,
n
.
Si fread
no devuelve el resultado esperado,
habrá que distinguir si es porque
llegamos al final del fichero o por un error; para ello
contamos con las funciones feof
y
ferror
para saber exactamente qué pasó,
que veremos a continuación.
La sintaxis de fwrite
es la siguiente:
#include <stdio.h> size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream);
ptr
hace referencia a un array con los datos que se van a
escribir al fichero abierto apuntado por stream
.
size
indica el tamaño de cada elemento del array.
n
especifica el número de elementos que se van a escribir.
stream
es un puntero a un fichero que ha tenido que haber
sido abierto previamente.
La función devuelve el número de elementos que se han escrito; luego si
no ha habido ningún error, ese número devuelto debería ser igual que el
tercer argumento, n
. El valor devuelto puede ser menos que
este n
si ha habido algún error.
Como se ha comentado anteriormente, tenemos la función feof
,
que se usa para saber cuándo hemos llegado al final del fichero:
#include <stdio.h> int feof(FILE *stream);
Esta función devuelve 0
si aún no se ha llegado al final
del fichero. Si se ha llegado, devuelve un entero distinto de cero.
Finalmente, contamos con la función ferror
para saber si
ha ocurrido algún error en la lectura o escritura, que devolverá
0
si no ha ocurrido ninguno y un valor distinto de cero
en caso contrario:
#include <stdio.h> int ferror(FILE *stream);
El siguiente programa escribe en bloque un array de números y luego los lee de uno en uno para calcular su suma.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | #include <stdio.h> #define TAM 6 int main(void) { FILE *fichero; int numeros[TAM] = {20, 20, 20, 20, 20, 20}; char nombre_fichero[] = "numeros.bin"; //Esta variable irá recogiendo los resultados de lectura/escritura size_t resultado; /* Abrimos para escritura en bloque*/ fichero = fopen(nombre_fichero, "w"); if (fichero == NULL) { printf("El fichero no se ha podido abrir para escritura.\n"); return -1; } // Se escribe en bloque los elementos del vector. resultado = fwrite(numeros, sizeof(int), TAM, fichero); if (resultado!=TAM) { printf("No se han escrito todos los %d números del array.\n", TAM); } if (fclose(fichero)!=0) { printf("No se ha podido cerrar el fichero.\n"); return -1; } /* Abrimos para lectura */ int suma = 0; fichero = fopen(nombre_fichero, "r"); if (fichero == NULL) { printf("El fichero no se ha podido abrir para lectura.\n"); return -1; } // Se lee número por número. int num; while (!feof(fichero)) { resultado = fread(&num, sizeof(int), 1, fichero); if (resultado != 1) { break; } suma = suma + num; } if (ferror(fichero)!=0) { printf("Ha ocurrido algún error en la lectura de números.\n"); } else { printf("La suma de los números leídos es: %d\n.",suma); } if (fclose(fichero)!=0) { printf("No se ha podido cerrar el fichero.\n"); return -1; } return 0; } |
A la hora de escribir el archivo, conocemos de antemano el tamaño del array y se puede escribir todo el bloque. En caso de que hubiera que escribir una serie de números, sin saber exactamente cuántos, se tendría que ir escribiendo uno por uno.
La sentencia break
de la línea 47 se usa para salir de la lectura,
pues ha habido un error o final de fichero y no se necesita efectuar
ninguna operación más dentro del bucle.
Al salir, se comprueba qué es lo que pasó realmente, para advertir
al usuario.