Sei sulla pagina 1di 6

Lectura y escritura de un fichero binario

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. o 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. o a o ab. Abre el fichero para aadirle datos al final. Respeta el contenido que tuviera. o 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. o w+, wb+ o w+b. Abre el fichero para lectura y escritura. Crea el fichero si no existe y machaca el contenido si existe. o 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; /* Apertura del fichero original, para lectura en binario*/ f1 = fopen ("fichero.dat", "rb"); if (f1==NULL) { perror("No se puede abrir fichero.dat"); return -1; } /* Apertura del fichero de destino, para escritura en binario*/ f2 = fopen ("fichero2.dat", "wb"); if (f2==NULL) { perror("No se puede abrir fichero2.dat"); return -1; } 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 /* Para meter lo que vamos leyendo del fichero */ char buffer[1000]; /* Para guardar el nmero de items leidos o si ha habido error */ int leidos; ... /* Lectura e if para detectar posibles errores */ 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)) /* Hemos llegado al final de fichero */ O mejor todava, se puede usar feof() como condicin del bucle while (!feof(f1)) { /* Hay datos disponibles para leer */ } 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)) { /* Tratar los datos ledos en buffer */ ... /* Y hacer otra lectura */ 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); /* Ahora hay que tratar los datos, pero si hemos llegado a final de fichero, NO hay datos que tratar. Hay que poner un fi para este caso */ if (!feof(f1)) {

/* Tratar los datos ledos */ ... } } 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)) { /* tratar los datos leidos */ } 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); /* Mientras se haya leido algo ... */ while (leidos!=0) { /* ... meterlo en el fichero destino */ fwrite (buffer, 1, leidos, f2); /* y leer siguiente bloque */ 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.

Potrebbero piacerti anche