Capítulo 12. Estructuras externas de datos: ficheros. Introducción



Descargar 136.35 Kb.
Fecha de conversión09.03.2017
Tamaño136.35 Kb.
Capítulo 12. Estructuras externas de datos: ficheros.
1. Introducción.

1.1. Ficheros de texto y binarios.


2. Declaración, apertura y cierre de ficheros.
3. Entrada/Salida con ficheros de texto.

3.1. Lectura/Escritura de caracteres.

3.2. Lectura/Escritura de cadenas de caracteres.

3.3. Lectura/Escritura con formato.


4. Entrada/Salida con ficheros binarios.
5. Otras funciones útiles sobre ficheros.
6. Ficheros estándares.

6.1. Redirección.



1. Introducción.

Hasta ahora los programas realizados permiten manejar datos procedentes del teclado, los cuales han sido almacenados en variables de memoria (RAM). Como sabemos, los datos contenidos en las variables de memoria se pierden al finalizar el programa que las utiliza. De esta manera no es posible guardar los datos introducidos durante una ejecución del programa para ser utilizados en futuras ejecuciones. Con el uso de ficheros (archivos) se puede solucionar ese problema, ya que los ficheros no residen en la memoria del ordenador.


Un fichero es una colección de datos organizados que se almacena en un soporte externo de almacenamiento masivo, como un disco duro, un disquete, un disco compacto, etc. Estos soportes no se borran cuando finaliza la ejecución del programa, ni siquiera cuando se apaga el ordenador, por tanto los datos de los ficheros se pueden utilizar en futuras ejecuciones del programa.
Una operación de salida o escritura de datos en un fichero será el paso de información desde una variable de memoria al fichero. Por el contrario, una operación de entrada o lectura de datos de un fichero será el paso de información desde el fichero a alguna variable de memoria. En C todas las operaciones de entrada y salida tienen lugar a través de funciones de la biblioteca estándar, las cuales están definidas en su mayor parte en la librería stdio.h.
1.1. Ficheros de texto y binarios.

En C se puede trabajar con los ficheros de dos modos: en modo texto y en modo binario. En modo texto los datos se graban en los ficheros en formato de texto, es decir como secuencia de caracteres. En modo binario los datos son grabados en su representación binaria, es decir como secuencia de bytes. Por ejemplo, si grabamos en un fichero el valor 16711 de tipo int, en modo texto se guardaría la secuencia de 5 caracteres “16711”, mientras que en modo binario se guardaría una secuencia de 2 bytes (int), los que corresponden a la representación binaria del valor 16711 con 16 bits:


16711 = 01000001 01000111

A G
Esos dos bytes, según el código ASCII, corresponden a los caracteres ‘A’ y ‘G’. Si editamos el fichero para ver el contenido del mismo en ese último caso, observaremos en pantalla “GA”, primero la G porque es el byte menos significativo.


Por otra parte, un final de línea, que se representa en C por un único carácter, el ‘\n’ (10 del ASCII), se traduce al escribirlo en un fichero en modo texto por dos caracteres: CR (Carriage Return o retorno de carro, 13 del ASCII) y LF(Line Feed o avance de línea, 10 del ASCII). Al leerse esos dos caracteres del fichero en modo texto ocurre la traducción inversa, obteniéndose el único carácter ‘\n’ del C. Sin embargo, esa traducción no tiene lugar en modo binario, por lo que al escribir el ‘\n’ se almacena solamente el LF, y al leer el LF se obtendrá el carácter ‘\n’.
2. Declaración, apertura y cierre de ficheros.

El acceso a un fichero se realiza siempre a través de un puntero. Este puntero apunta a una posición (byte) determinada del fichero, que es a la que se podrá acceder en ese momento. El puntero irá avanzando posiciones en el fichero automáticamente a medida que se van leyendo o escribiendo datos, por lo que apuntará siempre a la posición siguiente a la última leída o escrita. La declaración de un puntero a fichero se realiza usando el tipo FILE definido en stdio.h, de la siguiente forma:


FILE *
;

Ej.


FILE *pf; //pf será un puntero a un fichero.
Antes de utilizar un fichero en un programa, ya sea para escribir datos en él y/o para leer datos de él, el fichero debe ser abierto, con lo que se establece un canal de comunicación entre el programa y el fichero. La función para abrir un fichero se denomina fopen() y su sintaxis es:

= fopen(“”, “”);


Como puede verse, esta función devuelve un puntero a fichero,
,
que será el puntero que quede asociado al fichero abierto hasta que sea cerrado. Todas las operaciones sobre el fichero se realizarán a través de ese puntero
. Para indicar el fichero que se desea abrir se usa la cadena de caracteres , la cual puede incluir, además del nombre del fichero, la ruta completa donde está ubicado, es decir la unidad de almacenamiento y la carpeta. No olvidar que la barra invertida (\) de la ruta debe escribirse dos veces (\\), porque si se escribe sólo una vez es interpretada como secuencia de escape. Con la cadena se indicará si se va a usar el fichero en modo texto o en modo binario, además servirá para especificar si se va a leer del fichero, se va a escribir en él o ambas cosas. Se pueden emplear los siguientes modos de apertura:

Modo de apertura


F.Texto

F.Binario

Significado


r

rb

Abre un fichero para lectura (read)


w

wb

Crea un fichero para escritura (write)

a

ab

Abre un fichero para añadir (add)

r+

r+b

Abre un fichero para lectura/escritura

w+

w+b

Crea un fichero para lectura/escritura

a+

a+b

Abre o crea un fichero para lectura/escritura

Como puede verse en la tabla, los modos de apertura para ficheros en modo binario son los mismos que en modo texto, simplemente se le añade la letra ‘b’. El modo de apertura indicará qué debe hacer el sistema con el fichero, dependiendo de si existe o no. Por ejemplo, abrir para lectura un fichero que no exista producirá un error. Además el modo de apertura también establece donde apuntará el puntero al abrir el fichero, al principio o al final del mismo. Por ejemplo, si deseamos añadir datos al fichero, el puntero deberá colocarse al final, mientras que si queremos leer todos los datos, deberá colocarse al principio. Por otro lado, un fichero abierto para lectura no permitirá realizar escrituras en él, a no ser que se cierre y se vuelve a abrir para escritura. En la siguiente tabla se concretan todos estos casos.




F.Tex.

F.Bin.




Fichero ya existe

Fichero no existe

Lectura

Escritura

Posición Puntero

r

rb

Lectura

Correcto

* Error *

Correcto

* Error *

Principio

w

wb

Escritura

Borra contenido

Se crea

* Error *

Correcto

Principio

a

ab

Añadir

Correcto

Se crea

* Error *

Correcto

Final

r+

r+b

Lect/Esc

Correcto

* Error *

Correcto

Correcto

Principio

w+

w+b

Lect/Esc

Borra contenido

Se crea

Correcto

Correcto

Principio

a+

a+b

Lect/Añadir

Correcto

Se crea

Correcto

Correcto

Principio

En la tabla se observa que la apertura de un fichero con el modo w puede ser peligrosa, ya que si el fichero existe se perderán todos sus datos. Aunque hay situaciones en las que es esa acción precisamente la que se quiere realizar, destruir todos los datos previos del fichero. Por otra parte, debe tenerse en cuenta que si se utiliza el modo de apertura a o a+, los datos nuevos que se escriban en el fichero nunca sobrescriben otros datos, sino que siempre se añaden al final, aunque el puntero esté en otra posición. Esto se cumple tanto para ficheros de texto como para binarios. El puntero apuntará al final después de añadir los nuevos datos. Además, al abrir un fichero con el modo de apertura a, el puntero inicialmente se coloca al principio, aunque después de añadir algún dato el puntero automáticamente pasa al final.


Si la función fopen() tiene éxito, es decir abre el fichero sin ningún problema, devolverá el puntero al fichero. Por el contrario, si se ha producido algún error al intentar la apertura devuelve el valor NULL. Por tanto, después de ejecutar la función fopen(), el programa deberá comprobar siempre si el puntero devuelto vale NULL.
Ej.

FILE *fptr;

//Especificando sólo nombre de fichero...

if ((fptr = fopen("texto.txt", "w")) == NULL )

{

printf ( "ERROR" ); getch(); exit(1);



}

//Especificando unidad y nombre de fichero...

if ((fptr = fopen("C:cursos.dat", "r+b")) == NULL )

{

printf ( "ERROR" ); getch(); exit(1);



}

//Especificando unidad, carpeta y nombre de fichero...

if ((fptr=fopen("C:\\BC\\cursos.dat","a+b"))==NULL)

{

printf ( "ERROR" ); getch(); exit(1);



}
El standard ANSI C especifica que pueden estar abiertos 8 ficheros a la vez, aunque dependiendo del compilador este número puede ser mayor.
Cuando un programa deja de necesitar un fichero, éste debe cerrarse, cortándose por tanto el canal de comunicación entre el programa y el fichero. Para cerrar un fichero se utiliza la función fclose(), cuya sintaxis es:
fclose (
);
Lógicamente, se cerrará el fichero que tuviera asociado el puntero
. Este puntero quedará entonces disponible para ser utilizado en la apertura de cualquier otro fichero. En caso de éxito, fclose() devuelve un cero, mientras que cualquier otro valor devuelto indicará la existencia de algún error.
Ej.

FILE *ptr;

if ((fptr = fopen ("texto.txt", "w")) == NULL )

{

printf( "Error de apertura"); getch(); exit(1);



}

...


if (fclose(fptr) != 0)

{

printf( "Error de cierre"); getch(); exit(1);



}
En un fichero nunca se borran datos. Esto quiere decir que si se cierra un fichero con el puntero apuntando a una posición que no es la última, los datos que haya desde esa posición hasta el final del fichero no se borran. Por tanto, un fichero nunca disminuye su tamaño, sino que se mantiene o aumenta.
3. Entrada/Salida con ficheros de texto.

Veamos inicialmente las operaciones de lectura y escritura de caracteres individuales y posteriormente de cadenas. Aunque todas estas funciones pueden emplearse con ficheros binarios, lo normal es hacerlo con ficheros de texto. Más adelante serán comentadas las funciones que suelen emplearse con ficheros binarios.


3.1. Lectura/Escritura de caracteres.

Para la lectura de un único carácter de un fichero se usan las funciones fgetc() o getc(), las cuales son idénticas, no presentan ninguna diferencia. La sintaxis de ambas es la misma, por lo que sólo se expone la de una de ellas:


char car;

car = fgetc(


);
En la variable car quedará el carácter leído del fichero apuntado por
. Automáticamente el puntero avanzará a la posición siguiente del fichero. Después de leer el último carácter, al realizar una nueva lectura la función fgetc() devuelve el carácter EOF (End Of File), constante definida en stdio.h cuyo valor es –1 e indica que se ha llegado al final del fichero. La constante EOF está definida en mayúsculas. Para comprobar el final de un fichero es conveniente usar la función feof(), ya que los ficheros binarios pueden contener algún byte cuyo valor sea el mismo que el de EOF, sin ser el final del fichero. La función feof() será comentada más adelante.
Como se ha comentado en un apartado anterior, si se realiza la lectura de un salto de línea (CR + LF, 2 caracteres) de un fichero de texto, se obtiene el carácter ‘\n’ del C. Es decir si al ejecutar car = fgetc(
)
se detecta un salto de línea, se leen automáticamente los dos caracteres (CR y LF) y en car quedará el ‘\n’ (10 del ASCII).
Cuando la función fgetc() tiene éxito devuelve el carácter leído, pero si detecta algún error devuelve EOF. Por el mismo motivo citado previamente para los ficheros binarios, es conveniente emplear la función ferror() para detectar la presencia de algún error al realizar la lectura. Esta función será explicada más adelante.
Ej.
#include

#include

void main (void)

{

FILE *fp;



char car;

if ((fp = fopen (“C:LEEME.TXT”, "r" )) == NULL )

{

printf("Error de apertura.");getch();



exit(1);

}

car = fgetc(fp); //lee el primer carácter.



while ( car != EOF )

{

printf(“%c”, car);



car = fgetc(fp);

}

if (fclose(fp) != 0)



{

printf( "Error al cerrar fichero.");getch();

exit(1);

}

}


Para escribir un único carácter en un fichero se usan las funciones putc() o fputc(), las cuales son idénticas, por lo que se utilizan del mismo modo. La sintaxis es:
char car;

fputc( car,


);
Antes de realizar la escritura debe colocarse en la variable car el carácter que se desea escribir en el fichero que esté apuntado por
. El carácter será escrito en la posición del fichero donde esté apuntando el puntero, avanzando éste de posición automáticamente. Si en la posición donde se escribe un carácter ya existe otro, éste será sobrescrito. Sin embargo, si el fichero ha sido abierto con el modo a o a+ (add, añadir datos), los datos siempre se escriben al final del fichero, aunque el puntero esté en cualquier otra posición. Esto es así para todas las operaciones de escritura, tanto en ficheros de texto como binarios.
Si se desea escribir en un fichero un texto tecleado carácter a carácter, la tecla ENTER se graba como un CR sólo (13 del ASCII), no como salto de línea (CR+LF). Si se lee ese fichero abierto en modo texto, ese carácter CR se desprecia, como si no estuviera, pero si se lee el fichero abierto en modo binario, se recibe el carácter CR.
Cuando la función fputc() realiza la escritura con éxito devuelve el carácter escrito, pero si se produce algún error devolverá EOF. Es conveniente usar la función ferror() para detectar esta situación, como ya se ha comentado.
Ej.Escribir en un fichero los caracteres tecleados; al pulsar ENTER,

grabar un salto de línea. Se finalizará al pulsar ESCAPE.


#include

#include

void main (void)

{

FILE *fp;



char car;

if ((fp = fopen (“TEXTO.TXT, "w" )) == NULL )

{

printf("Error de apertura.");getch();



exit(1);

}

clrscr();printf(“Texto a escribir en fichero:”);



while ((car = getche()) != 27)

{

if (car == 13) //Si se pulsa ENTER, escribe



fputc(‘\n’, fp); // CR + LF

else


fputc(car, fp);

if (ferror(fp)) //Comprueba si hay error

{

printf(“Error de escritura.”); getch();



exit(1);

}

}



if (fclose(fp) != 0)

{

printf( "Error al cerrar fichero.");getch();



exit(1);

}

}


3.2. Lectura/Escritura de cadenas de caracteres.

La función fgets() permite leer una cadena de caracteres de un fichero. La sintaxis de esta función es:


char cad[80];

fgets( cad, ,


);
El número de caracteres que se leen del fichero
es -1 y quedan cargados en la cadena de caracteres cad. El carácter fin de cadena ‘\0’ se añade automáticamente al final de la cadena. La lectura de un salto de línea (CR + LF) del fichero provoca que la función fgets() no lea más caracteres, aunque no haya cumplido la lectura del número de caracteres especificado por -1. Un salto de línea que sea leído (CR + LF) del fichero quedará almacenado en la cadena como el carácter ‘\n’ (10 del ASCII) y a continuación se almacena el carácter de fin de cadena ‘\0’.
Cuando la función fgets() realiza una lectura y encuentra el carácter fin de fichero, EOF, éste no es almacenado en la cadena, sino que se finaliza la misma con el ‘\0’.
Si la función fgets() tiene éxito devuelve un puntero a la cadena cad. Si se produce algún error devuelve el puntero nulo (NULL), quedando el contenido de cad indeterminado. Cuando se encuentra el final del fichero, la función fgets() también devuelve puntero nulo, por lo que es conveniente utilizar las funciones feof() y ferror() para distinguir si se ha producido algún error o se ha leído el fin del fichero.
Ej.
#include

#include

void main ( void )

{

FILE *fp;



char cad[80]; //En cad caben 79 caracteres.

if (( fp = fopen("texto.txt", "r" )) == NULL )

{

printf("No se puede abrir fichero\n");



getch();exit(1);

}

while (!feof(fp)) //Se leen 79 caracteres:80-1



if (fgets(cad,80,fp)!=NULL)

printf("%s", cad);

if (fclose(fp) != 0)

{

printf( "Error al cerrar fichero.");getch();



exit(1);

}

}


La función fputs() permite escribir una cadena de caracteres en un fichero. La sintaxis de esta función es:
char cad[80];

fputs (cad,


);
La cadena de caracteres cad será escrita en el fichero
, en la posición donde esté apuntando el puntero de ese fichero, excepto si se ha abierto con a o a+, en cuyo caso la cadena se añade al final del fichero. El carácter fin de cadena ‘\0’, que es el último almacenado en cad, no es escrito en el fichero. Si la cadena cad contiene el carácter ‘\n’ (10 de ASCII), en el fichero se escribirán los caracteres CR y LF (salto de línea).
Si al ejecutar fputs() se produce algún error, esta función devuelve un valor distinto de cero, pero en caso de éxito devolverá 0.
Ej.Escribir cada cadena tecleada al fichero TEXTO.TXT.
#include

#include

#include

void main ( void )

{

FILE *fp;



char cad[80];

if ((fp = fopen("C:texto.txt","w")) == NULL)

{

printf("No se puede abrir fichero\n");



getch(); exit(1);

}

do



{

printf("Teclee cadena:\n");

scanf(“%79[^\n]”, cad);fflush(stdin);

strcat(cad,"\n"); //Añade \n a cad.

if (fputs(cad, fp) != 0)

exit(1); //En el fichero se escribe

//una cadena en cada línea.

} while (cad[0] != '\n');

if (fclose(fp) != 0)

{

printf( "Error al cerrar fichero.");



getch(); exit(1);

}

}


3.3. Lectura/Escritura con formato.

Las funciones fprintf() y fscanf() son idénticas a sus homólogas printf() y scanf(), pero con la excepción de que permiten realizar operaciones de lectura y escritura con cualquier fichero. La función printf() permite escribir sólo en la pantalla y la función scanf() permite leer sólo desde teclado.


Las sintaxis de estas funciones son:
fprintf(
,, );

fscanf (
,, );


Como puede verse la sintaxis coincide con la de las funciones printf() y scanf(), excepto que ahora presentan un parámetro nuevo,
, que permite especificar con qué fichero se desea realizar la lectura con fscanf() o la escritura con fprintf(). La y la se utilizan como ya fue explicado para las funciones printf() y scanf().
La función fprintf() convierte todos los datos a formato texto antes de escribirlos en el fichero, es decir no escribe en binario.
Ej.
int num = 123;

fprintf(fp, “%3d”, num);


En ese ejemplo, el número 123 de tipo int 123 almacenado en num (ocupa 2 bytes), se grabará en el fichero en modo texto, es decir se guardarán los tres caracteres 1, 2 y 3 (ocupan 3 bytes), no se guardan los 2 bytes (int) donde está codificado el valor 123.
De forma análoga, la función fscanf() lee del fichero siempre en modo texto, para posteriormente convertirlo al formato que se haya especificado en la .
Ej.

int num;


fscanf(fp,”%2d”, &num); //Lee 2 caracteres del fichero
En ese ejemplo, si leemos el fichero anterior donde se han escrito los caracteres “123” con la función fprintf(), después del fscanf() en num quedará almacenado el valor 12 ya convertido a tipo int. Debe recordarse que la función fscanf() espera la dirección de los variables, es decir &num en este ejemplo. Cuando la función fscanf() intenta leer del fichero caracteres que no pueden ser convertidos al tipo especificado en , no lee nada, dejando en la variable donde se iba almacenar la lectura el valor que tuviera antes de ejecutar fscanf().
Ej.

long num = 77;

fscanf(fp,”%2ld”,&num);
En ese ejemplo, si los dos caracteres que se intentan leer del fichero son letras, por ejemplo AB, no serán leídos ya que num es variable numérica (%2ld). En num se mantiene el valor previo, 77. El puntero del fichero no se desplaza, es decir las letras AB serán leídas en la próxima operación de lectura, siempre que la variable donde serán guardadas sea una cadena de caracteres (%2s).
La función fprintf() devuelve el número de caracteres escritos cuando tiene éxito. En caso contrario devuelve un número negativo. La función fscanf() devuelve el número de variables donde se han guardado correctamente los valores leídos del fichero. Cuando a ninguna variable le ha asignado un valor devuelve 0. Si fscanf() detecta el final del fichero devolverá EOF.
A pesar de ser las funciones más fáciles de usar para lectura/escritura en ficheros, no son las más usadas debido a estas conversiones que se han comentado y que realizan antes de escribir en el fichero (fprintf()) o después de leer del fichero (fscanf()). En esas conversiones se consume tiempo, por tanto no es lo más eficiente. Así cuando sea importante la velocidad del programa y el tamaño del fichero sea grande se emplearán las funciones fread() y fwrite() que veremos más adelante.
Ej. Lee el contenido de un fichero y lo escribe en otro.
#include

#include

#include

void main ( void )

{

char car;



FILE * fp1, * fp2;

if ((fp1 = fopen("entra.dat", "r")) == NULL )

{

printf("No se puede abrir.\n");



getch(); exit(1);

}

if ((fp2 = fopen("sale.dat", "w")) == NULL )



{

printf("No se puede abrir.\n");

getch(); exit(1);

}
while (fscanf(fp1, "%c", &car) != EOF )

fprintf(fp2, "%c", car);
if (fclose(fp1) != 0)

{

printf( "Error al cerrar fichero.");



getch(); exit(1);

}

if (fclose(fp2) != 0)



{

printf( "Error al cerrar fichero.");

getch(); exit(1);

}

}


4. Entrada/Salida con ficheros binarios.

Ya ha sido comentado que en un fichero binario los datos son grabados como sucesión de bytes, es decir tal y como están en memoria RAM. Por ejemplo, una variable de tipo float en un fichero binario siempre ocupará 4 bytes, independientemente del valor de dicha variable. Esos 4 bytes serán la representación en coma flotante de dicho valor. En un fichero de texto todo se graba como una sucesión de caracteres, por lo que si el valor de tipo float es 12.0935, ocupará 7 bytes (7 caracteres) en el fichero de texto (en lugar de 4 bytes). El punto decimal también ocupará un byte.


La función fread() permite leer una serie de bytes de un fichero, ya sea de texto o binario, sin realizar ningún tipo de conversión. Esto significa que en el caso de ficheros binarios, se pueden leer los datos en el formato en que fueron grabados. Por ejemplo, para leer una cantidad numérica que fue escrita en el fichero con el tipo float, habrá que leer 4 bytes. La sintaxis de esta función es:
fread( , , ,
);
Se leerán del fichero
el número de bytes tantas veces como indique , dejando dichos bytes grabados en memoria a partir de la dirección . Esta dirección será la de una variable con el tamaño suficiente para guardar los datos leídos. El número de bytes que se leen será por tanto el resultado del producto: * .
Ej.

int num;


fread(&num, sizeof(int), 1, fp);

//Se leen 2*1=2 bytes del fichero, que caben en num.


float Notas[5];

fread(Notas, sizeof(float), 5, fp);

//Se leen 4*5=20 bytes del fichero, que caben en Notas
En ese ejemplo, en el segundo caso se leerán 20 bytes, ya que se leen 5 veces el número de bytes indicado por sizeof(float), o sea 4*5 = 20. Por tanto, se leen 5 números float desde el fichero y se guardan en el array Notas, cuyo tamaño es de 20 bytes.
La función fread() devuelve un valor que indica cuántas veces ha leído el , que no siempre coincide con , ya que ha podido detectarse el final del fichero o producirse un error antes de cumplir la lectura de todas las veces indicadas en . Por tanto, si el valor devuelto es menor que significa que ha habido algún error o ha llegado el fin del fichero. Es conveniente usar las funciones ferror() y feof() para distinguir qué ha ocurrido.
Cuando el fichero ha sido abierto en modo texto, si fread() lee un salto de línea (CR + LF), estos dos caracteres se convierten automáticamente al carácter ‘\n’ (10 del ASCII). Cuando el fichero ha sido abierto en modo binario, no se produce conversión, por lo que se leen los dos caracteres, CR (13 del ASCII) y LF (10 del ASCII).
La función fwrite() permite escribir datos en un fichero como una sucesión de bytes, sin ser convertidos a texto. La sintaxis de esta función es:
fwrite( , , ,
);
A partir de la dirección de memoria se leerán tantos bytes como se indique en tantas veces como se especifique en y se escribirán en el fichero <pf>. El número de bytes escritos será por tanto el resultado del producto: * .
Ej.

int num=1067;

fwrite(&num, sizeof(int), 1, fp);

//Graba 2 bytes en el fichero, desde la dirección num,

//por tanto el valor 1067 queda escrito en el fichero.
float Notas[5]={5.5, 7.25, 8.5, 4.75, 9.5};

fwrite(Notas, sizeof(float), 5, fp);

//Se escriben 4*5=20 bytes en el fichero, desde la

//dirección Notas, quedando las 5 notas grabadas en el

//fichero.
La función fwrite() devuelve el número de veces que ha escrito el , que no siempre coincide con , ya que puede producirse algún error. Por tanto, si el valor que devuelve fwrite() no coincide con es que ha ocurrido un error.

Ej.Escribir un número real en un fichero. Leerlo en otra variable real.

FILE *fp;

float var;

float num = 12.23;

if ((fp = fopen("prueba.dat", "wb")) == NULL )

{

printf("No se puede abrir.\n");



getch(); exit(1);

}

fwrite( &num, sizeof(float), 1, fp);



fclose(fp);

if ((fp = fopen("prueba.dat", "rb")) == NULL )

{

printf("No se puede abrir.\n");



getch(); exit(1);

}

fread (&var, sizeof(float), 1, fp );



fclose(fp);
Uno de los usos más comunes de fread() y fwrite() es el manejo de ficheros en forma de conjunto de registros, donde cada registro está dividido en campos. Para ello en el programa debe definirse un tipo de estructura con el mismo formato que el registro del fichero, con el objeto de leer y escribir registros completos con las funciones fread() y fwrite() respectivamente, en lugar de leer y escribir campos concretos.


Ej. Teniendo un array de estructuras ya cargado con datos, deberá

grabarse en un fichero y después dejarlo en otro array de estructuras.

struct t_lista {

char nombre[20];

char apellido[40];

} lista1[30], lista2[30]; // 30 estructuras, 2 veces.

//Suponemos que lista1 ya contiene datos.


void grabar_leer (void )

{

FILE *fp;



int i;

if ( (fp = fopen("fich.dat", "wb")) == NULL )

{

printf("No se puede abrir.\n");



getch(); exit(1);

}

//Escribe 30 registros desde el array lista1.



for ( i = 0; i < 30; i++)

if (fwrite(&lista1[i],sizeof(struct t_lista),1,fp)!=1)

printf("Error de escritura");

fclose(fp);

if ( (fp = fopen("fich.dat", "rb")) == NULL )

{

printf("No se puede abrir.\n");



getch(); exit(1);

}

//Lee 30 registros, dejándolos en el array lista2.



for ( i = 0; i < 30; i++)

if (fread(&lista2[i], sizeof(struct t_lista),1,fp)!=1)

printf("Error de lectura");

fclose(fp);

}
5. Otras funciones útiles sobre ficheros.

La función feof() permite conocer si la última lectura se ha realizado del final del fichero, por lo que para conocer si se ha llegado al final, previamente debe realizarse una lectura. La sintaxis de esta función es:


int fin_f;

fin_f = feof(


);
Si devuelve un valor distinto de 0 (verdadero) significa que el puntero del fichero está en el final del mismo. En otro caso la función devuelve 0 (falso).
Como ya se ha explicado, en un fichero binario se puede leer un valor entero igual al valor de EOF, por lo que alguna rutina de lectura que finalice al encontrar EOF podría acabar realmente antes de llegar al final físico del fichero. Por ello es conveniente usar la función feof().
La función ferror() indica si se ha producido algún error en una operación de lectura o escritura sobre un fichero. Su sintaxis es:
int error;

error = ferror(


);
Si devuelve el valor 0 (falso) significa que no ha ocurrido ningún error y un valor distinto de 0 (verdadero) en caso contrario.
La función rewind() permite colocar el puntero al principio del fichero. Su sintaxis es:
rewind(
);
Como sabemos, en un fichero sólo se puede acceder, ya sea para leer o escribir, a la posición que indique el puntero. Con la función rewind() podemos llevar ese puntero al principio. Además esta función inicializa los indicadores de fin de fichero y de error asociados al fichero en cuestión. No devuelve ningún valor.
Ej.Cargar cadenas tecleadas en un fichero y posteriormente leerlas y

visualizarlas, sin cerrar y volver a abrir el fichero.


#include

#include

#include

void main ( void )

{

char cadena[80];


FILE *fp; //se abre para lectura/escritura


if ((fp=fopen("datos.dat", "w+")) == NULL )

{

printf("No se puede abrir\n");



getch(); exit(1);

}

do



{

printf("Teclee una cadena:\n");

scanf(“%79[^\n]”, cadena); fflush(stdin);

strcat(cadena,"\n"); //Cada cadena en una

fputs(cadena,fp); //línea distinta. } while ( cadena[0] != '\n' );

rewind(fp); //Se coloca al principio del fichero.

fgets(cadena,79,fp);

while ( !feof(fp) )

{

printf("%s",cadena);



fgets(cadena,79,fp);

}

fclose(fp);



}
La función remove() permite borrar un fichero del disco, no sólo su contenido. Su sintaxis es:
remove( );
El parámetro será una cadena de caracteres que contiene el nombre del fichero a borrar. En caso de éxito esta función devuelve 0 y distinto de cero en caso contrario.
Ej.

char cad[80];

printf("Teclee fichero a borrar:");

scanf("%s", cad);

if ( ! remove(cad) )

printf("Fichero borrado.");

else

printf("Error al borrar.");


La función rename() permite cambiar el nombre de un fichero, el cual puede estar abierto o cerrado. Su sintaxis es:
rename(NombreActual, NombreNuevo);
Los parámetros NombreActual y NombreNuevo son dos cadenas que contienen los nombres actual y nuevo del fichero respectivamente.
Ej.
char cad[]= “DNI.DAT”;

rename(“CODIGOS.DAT”, cad); //El fichero llamado

//CODIGOS.DAT pasará a llamarse DNI.DAT.
La función fseek() permitirá colocar el puntero del fichero en una posición determinada, para acceder al fichero a partir de esa posición. Su sintaxis es:
fseek(
, , );
El puntero se colocará en la posición del fichero
que corresponda a desplazarse el número de bytes indicado por partiendo desde la posición indicada por . La primera posición del fichero es la 0, no la 1. El valor debe ser de tipo long, por lo que si se usa un valor literal debe escribirse una L después de dicho valor, por ejemplo -7L para desplazarse 7 bytes hacia atrás desde <origen>. Si en lugar de un literal, se usa una variable que no sea long, podrá convertirse colocando (long) antes de dicha variable, (long)Var.
El puede tomar los valores 0, 1 o 2, a los que se les han asociado unas constantes definidas en stdio.h, para facilitar el uso:
SEEK_SET principio del fichero (valor entero 0).

SEEK_CUR posición actual del puntero (valor entero 1).

SEEK_END final del fichero (valor entero 2).
La función fseek() devuelve 0 en caso de éxito y un valor distinto de 0 en el caso contrario.
Ej.

fseek(fp,0L,SEEK_SET); //Colocar puntero al principio

fseek(fp,-5L,SEEK_CUR); //Retroceder 5 posiciones

fseek(fp,0L,SEEK_END); //Colocar puntero al final


Ej.
#include

#include

void main ( void )

{

FILE *fp;



if ( (fp=fopen("fichero.dat", "r")) == NULL )

{

printf("Error al abrir fichero.");



getch(); exit(1);

}

if ( fseek(fp, 202L, SEEK_SET) )



{

printf("Error de posicionamiento");

exit(1);

}

printf("El byte %d es %c \n", 202, fgetc(fp));



fclose(fp);

}
Como sabemos, el carácter '\n' escrito en un fichero binario ocupa de 1 byte (10 del ASCII), que corresponde a una posición, mientras que en un fichero de texto ocupa de 2 bytes (CR y LF), o sea 2 posiciones.


La función ftell() permite obtener la posición actual a la que esté apuntando el puntero del fichero, contando el número de bytes que hay desde el principio del fichero hasta la posición actual del puntero. Su sintaxis es:
long pos;

pos = ftell(


);
Esta función devuelve -1 cuando se ha producido algún error.
Ej.

long i;


i = ftell(fp);

if (i == -1)

printf("Error");

else


printf("Esta en el byte %ld del fichero", i);
6. Ficheros estándares.

Al ejecutar un programa en C se abren automáticamente los ficheros estándares siguientes:


stdin fichero estándar de entrada (teclado).

stdout fichero estándar de salida (monitor).

stderr fichero estándar de salida de errores (monitor).

stdprn fichero estándar de impresión (puerto paralelo, impresora).
Según eso, las siguientes instrucciones son equivalentes:
printf(“%3d”, num);

fprintf(stdout, “%3d”, num);


Esos ficheros también se cierran automáticamente cuando el programa finaliza.
Para imprimir cualquier información desde dentro de un programa puede usarse la función fprintf() de la forma:
fprintf(stdprn, “...”, ...);
6.1. Redirección.

La función freopen() permite cerrar un fichero y abrir otro usando el mismo puntero. Su sintaxis es:


FILE *
;

freopen(, ,


);
Si
está ocupado con algún fichero, éste será cerrado y a continuación se abrirá el fichero especificado en con el modo de apertura indicado en .
La función freopen() puede utilizarse para redireccionar un fichero estándar. Los dispositivos citados en el apartado anterior, teclado, monitor e impresora, pueden ser redirigidos, de forma que se les pueden asignar otros ficheros. De esta forma podremos, por ejemplo, hacer que un listado por pantalla no se muestre en pantalla sino que quede grabado en un fichero en disco.
Ej.
void main ( void )

{

char cad[80];



//Redirigimos stdout hacia fichero salida.txt

freopen("C:salida.txt", "w", stdout);

//A partir de ahora, cualquier función de

//visualización en pantalla, como printf, envía

//los datos al fichero salida.txt.
printf(“DNI NOMBRE DIRECCIÓN”);

printf(“-------- ---------------- ------------”);

while (...)

{

printf(“%8ld ”, dni);



printf(“%-16s ”, nombre);

printf(“%12s\n”, direccion);

...

}//Esos datos se graban en el fichero salida.txt.



}
EJERCICIOS - CAPITULO 12:
Realizar los siguientes algoritmos en pseudocódigo y en C:


  1. Introducir desde teclado un texto en un fichero, carácter a carácter. Dicho texto puede estar formado por varias líneas y deberá visualizarse en pantalla correctamente a medida que se va tecleando. Sólo se guardará en el fichero los caracteres imprimibles del ASCII. Deberá controlarse la tecla y las teclas de control y de función. La tecla Escape se usará para finalizar la entrada de texto. Si el fichero existe, visualizar su contenido y añadir texto nuevo al final; si no existe, crearlo. El nombre del fichero deberá teclearse al comienzo del programa.




  1. Abrir un fichero de texto existente y visualizar cuántos bytes, caracteres, palabras y líneas tiene. Escribirlo completo en otro fichero pasando a mayúsculas todas las letras.




  1. Teclear una palabra y visualizar cuántas veces aparece en un fichero de texto.




  1. Escribir en dos ficheros binarios cantidades de tipo long de forma ordenada en cada fichero por separado. A continuación crear un tercer fichero binario donde queden todas las cantidades ordenadas, mezclando los dos primeros ficheros. Los nombres de los tres ficheros serán tecleados en la línea de órdenes, a continuación del nombre del programa al ejecutarlo.




  1. Escribir en un fichero binario el dni y el nombre de personas, sin usar estructuras. Después el programa permitirá visualizar el nombre cuyo dni sea tecleado, en bucle hasta que se teclee un 0.




  1. Cargar en un fichero en modo registro (estructuras) el código, nombre y las 11 notas de los alumnos de una clase. Visualizar al final los nombres de los alumnos con mayor y menor nota media.




  1. Hacer funcionar el siguiente menú sobre un fichero binario. Los campos de cada registro son: DNI, nombre, teléfono y sueldo. Si un DNI ya existe no permitirá añadirlo.

MENU:

Añadir empleado.

Borrar empleado.

Consultar empleado.

Sueldo medio entre todos los empleados.

Finalizar.




  1. Guardar en un fichero binario el código, nombre, 11 notas y el código del curso en el que están los alumnos de un centro. En otro fichero binario deberá guardarse el código de cada curso y el nombre de su tutor. Al final deberá visualizarse el nombre, la nota media y nombre del tutor del alumno cuyo código sea tecleado, hasta que se teclee un 0.









Compartir con tus amigos:


La base de datos está protegida por derechos de autor ©bazica.org 2019
enviar mensaje

    Página principal