You are on page 1of 7

Lectura y escritura de un fichero binario

En este tutorial vamos a hacer un programa en C que copie un fichero. Al hacerlo


aprovecharemos para ver lo bsico de lectura y escritura de ficheros binarios en C.
En linux tenemos dos grupos de funciones para lectura y escritura de ficheros. Las
funciones open(), write(), read() y close() son de algo ms bajo nivel y especficas de linux,
as que no las usaremos en este ejemplo. En su lugar
usaremos fopen(), fwrite(), fread() y fclose(), que son estndar de C y estn presentes en
todos los compiladores.

Abrir fichero
Lo primero de todo es abrir el fichero. Eso de abrir no es nada ms que decirle al sistema
operativo que prepare todo lo necesario para trabajar con un fichero concreto. Tendremos que
abrir tanto el fichero que queremos leer como uno nuevo en el que escribiremos la copia del
primero.
Un fichero tradicionalmente puede abrirse en modo texto o modo binario. No hay diferencia
real entre uno y otro, salvo que en un fichero en modo texto se supone que hay fines de lnea
y en un momento dado hay funciones de ficheros que pueden buscarlos. Si se abre en modo
binario, la informacin puede ser de cualquier tipo y las funciones de ficheros no buscarn
fines de lnea. Digo "tradicionalmente" porque en la prctica no hay ninguna diferencia entre
abrirlo de una manera o de otra. Por convencin, si el fichero es de texto legible se abre en
modo texto. Si el fichero no es de texto legible, se abre en modo binario.
La funcin que nos permite abrir un fichero es fopen(). Sus parmetros son:

Nombre del fichero que queremos abrir, con path absoluto o relativo.

Modo de apertura (lo abrimos para leer, para escribir, etc). Si el modo pone b se abre
en binario. Si no lo pone se abre en modo texto. Los posibles modos son:
o

r o rb: Abre el fichero para lectura. El fichero debe existir o tendremos un error.

w o wb. Abre el fichero para escribir en l. Puede o no existir. Si existe se


machaca el contenido que hubiera. Si no existe se crea.

a o ab. Abre el fichero para aadirle datos al final. Respeta el contenido que
tuviera.

r+, rb+ o r+b. Abre el fichero para lectura y escritura (el + es el que indica que
es para lectura y escritura a la vez). El fichero debe existir y respeta el
contenido, aunque si escribimos algo iremos machacando datos.

w+, wb+ o w+b. Abre el fichero para lectura y escritura. Crea el fichero si no
existe y machaca el contenido si existe.

a+, ab+ o a+b. Abre el fichero para lecturay y escritura. La escritura comenzar
al final del fichero, respetando el contenido.

La funcin fopen() nos devuelve un FILE*. Esto no es ms que un puntero a una estructura
que contiene informacin sobre el fichero recin abierto. Normalmente podemos ignorar esa
informacin, pero debemos hacer dos cosas con ese FILE* devuelto:

Comprobar que no es NULL. Si es NULL es que ha habido algn problema y el fichero


no se ha podido abrir (se ha abierto un fichero para leer que no existe, se ha abierto
para escritura en un directorio en el que no tenemos permiso de escritura, etc).

Guardarlo, porque es el puntero que requieren las dems funciones para saber sobre
qu fichero escribir o leer. Nos servir, desde el momento que lo abrimos, para
identificar el fichero con el que queremos trabajar.

Para nuestro ejemplo, abriremos el fichero original como lectura y el fichero en el que haremos
la copia como escritura. Puesto que nos da igual si el fichero es de texto o no, lo abriremos
como binario, ya que es ms general (un fichero de texto, con fines de lnea, no es ms que
un caso particular de un fichero binario, que tiene bytes).
#include<stdio.h>
...
FILE*f1,*f2;
/*Aperturadelficherooriginal,paralecturaenbinario*/
f1=fopen("fichero.dat","rb");
if(f1==NULL)
{
perror("Nosepuedeabrirfichero.dat");
return1;
}
/*Aperturadelficherodedestino,paraescrituraenbinario*/

f2=fopen("fichero2.dat","wb");
if(f2==NULL)
{
perror("Nosepuedeabrirfichero2.dat");
return1;
}
Ya est. f1 es el fichero origen y f2 es la copia.
Lectura del fichero binario
Para leer bytes de un fichero, sin importarnos si hay o no fines de lnea, podemos usar la
funcin fread(). Esta funcin tiene los siguientes parmetros

void *ptr. Un puntero a una zona de memoria donde se guardarn los datos leidos del
fichero. Nosotros pasaremos un array que hayamos creado previamente. En este array
nos dejar la funcin los datos que leamos del fichero. El puntero es de tipo void para
indicar que podemos pasar un puntero a cualquier tipo de dato que queramos.
Nosotros pasaremos uno de char *.

size_t size. El tamao en bytes de los datos que vamos a leer. En nuestro caso, como
queremos leer bytes, este valor ser 1.

size_t nitems. Numero de datos que queremos leer. El numero de datos que
queremos leer multiplicado por el tamao en bytes de cada dato, es decir, el nmero
total de bytes a leer, no puede exceder el tamao del array que pasemos como primer
parmetro o tendremos efectos extraos en nuestro programa. Como el array que
crearemos ser de 1000 char, el numero de items maximo que podemos leer de golpe
son 1000 (el tamao del char es 1).

FILE *stream. Recuerdas lo que nos devolva fopen()?. Pues tenemos que ponerlo
aqu.

La funcin fread() devuelve el nmero de elementos leidos, que debera ser igual a nitems.

Si en el fichero hay tantos o ms elementos como los que hemos mandado leer con
nitems, fread() los lee y devuelve nitems.

Si no hay tantos elementos en el fichero, devolver el nmero de elementos leidos que


ser menor que nitems.

Si devuelve 0 es que no ha leido ningn elmento porque se ha llegado al final de


fichero (se han terminado los datos del fichero).

Si devuelve -1 es que ha habido algn error.

El cdigo de lectura puede ser as


/*Parameterloquevamosleyendodelfichero*/
charbuffer[1000];
/*Paraguardarelnmerodeitemsleidososihahabidoerror*/
intleidos;
...
/*Lecturaeifparadetectarposibleserrores*/
leidos=fread(buffer,1,1000,f1);
if(leidos==...)
Escribir un fichero binario
Para escribir un fichero binario, usamos la funcin fwrite(). Los parmetros son los mismos
que fread(), pero con las siguientes salvedades

void *ptr. El puntero a la zona de memoria. Debe estar relleno con los datos que
queramos escribir en el fichero.

size_t size y size_t nitems indican tamao del elemento a escribir (1 en nuestro caso,
ya que usamos char) y cuantos elementos queremos escribir. El nmero de elementos
que queremos escribir son los que realmente hay en ptr, NO el tamao del array ptr.
Puede ser un array muy grande en el que slo hemos rellenado tres elementos, as
que nitems ser tres.

Consabido FILE *stream.

La funcin fwrite() nos devuelve el nmero de elementos escritos en el fichero o -1 si ha


habido algn error.
En nuestro ejemplo, teniendo en cuenta que el nmero de elementos que tenemos disponibles
en el array es el "leidos" que nos guardamos de la funcin fread(), el cdigo de escritura
quedara as
fwrite(buffer,1,leidos,f2);

Bucle hasta el fin de fichero


Ya sabemos lo bsico para leer y escribir. Como queremos hacer una copia, debemos leer el
fichero de entrada hasta que se termine e ir escribiendo en el fichero de salida. Para ello,
debemos hacer un bucle hasta el final de fichero en el que se lean datos de un lado y se
escriban en otro.
Aunque no la usaremos, hay una funcin feof(FILE *stream) a la que pasndole el dichoso
FILE* del fichero, nos devuelve 0 si hay datos para leer u otro valor si el fichero se ha
terminado. Por ello, un if bastara para saber si hemos llegado al final de fichero
if(feof(f1))
/*Hemosllegadoalfinaldefichero*/
O mejor todava, se puede usar feof() como condicin del bucle
while(!feof(f1))
{
/*Haydatosdisponiblesparaleer*/
}
Hay un pequeo problema que suele ser metedura de pata comn para los principiantes.
Hasta que no hagamos una lectura, NO podemos saber si se ha terminado el fichero. La
funcin fopen() slo abre el fichero, no comprueba si hay datos o no. La funcin feof() no mira
el fichero, sino simplemente si la ltma lectura ha llegado o no al final del fichero. Si usamos
feof() ANTES de hacer una lectura (con fread() en nuestro caso), SIEMPRE obtendremos que
hay datos disponibles.
Por ello, es necesario hacer un fread() (o cualquier otra funcin de lectura) ANTES de
empezar el bucle.
leidos=fread(buffer,1,1000,f1);
while(!feof(f1))
{
/*Tratarlosdatosledosenbuffer*/
...
/*Yhacerotralectura*/
leidos=fread(buffer,1,1000,f1);
}
Parece un poco feo, pero tampoco es elegante usar un do...loop, ya que deberamos meter un
if entre medias

do
{
leidos=fread(buffer,1,1000,f1);
/*Ahorahayquetratarlosdatos,perosihemosllegadoafinal
defichero,NOhaydatosquetratar.Hayqueponerunfiparaeste
caso*/
if(!feof(f1))
{
/*Tratarlosdatosledos*/
...
}
}while(!feof(f1))
En fin, es cuestin de gustos y puedes usar la opcin que ms te guste o cualquier otra que se
te ocurra. Lo importante es saber que hay que hacer al menos una lectura antes de utilizar
feof().
Dije, de todas formas, que no iba a usar feof(). Por qu?. Imagina que hay 10 bytes en el
fichero y slo 10 bytes. Cuando haga esta lectura
leidos=fread(buffer,1,1000,f1);
while(!feof(f1))
{
/*tratarlosdatosleidos*/
}
se leern los 10 bytes y leidos tendr 10. Pero como hemos llegado a final de fichero, feof()
ser cierto. Si me fio de feof() para terminar, no entrar en el bucle y no tratar esos 10 bytes.
En nuestro ejemplo, haremos el bucle mientras leidos sea mayor que 0. Si es cero, se ha
acabado el fichero, si es -1 ha habido algn error.
leidos=fread(buffer,1,1000,f1);
/*Mientrassehayaleidoalgo...*/
while(leidos!=0)
{
/*...meterloenelficherodestino*/
fwrite(buffer,1,leidos,f2);
/*yleersiguientebloque*/

leidos=fread(buffer,1,1000,f1);
}
Cerrar ficheros
Cuando terminamos de usar un fichero, hay que cerrarlo con fclose(FILE *). Unas tonteras
sobre fclose() para que las tengas en cuenta.
Cuando se termina nuestro programa, el sistema operativo cierra todos los ficheros que
tengamos abiertos. En principio, para un programa tonto como este, fclose() puede no
ponerse sin problemas.
Sin embargo, conviene acostumbrarse a ponerlo para no meter la pata en programas ms
grandes y complejos. Hay dos posibles problemas si no se pone fclose().

Hay un mximo de ficheros que se pueden abrir a la vez. Si nuestro programa es


grande, va abriendo ficheros y los va dejando abiertos, llegar un momento en que
alcanzaremos ese lmite y tendremos un error. Este mximo es grande, pero no
demasiado. Supongo que depende del sistema operativo concreto que usemos, pero
puede ser del orden de 32, 64, etc. Vaya, que si nos despistamos, podemos llegar a l
con cierta facilidad.

Al cerrar el fichero nos aseguramos que su contenido realmente se esribe en el disco


duro. Si nuestro programa no cierra el fichero, es posible que los datos no estn
realmente en el disco duro y otros programas que vayan a acceder a ellos no los
encuentren.

As, que siguiendo las buenas constumbres...


fclose(f1);
fclose(f2);
Vamos ahora a un caso un poco ms complejo, cmo acceder a cualquier posicin del
fichero de golpe.

You might also like