Professional Documents
Culture Documents
(2)
(unidad 7)
archivos
(7.1) esquema de la unidad
(7.1) esquema de la unidad _____________________________________________________________ 3
(7.2) introducción_______________________________________________________________________ 4
(7.2.1) archivos 4
(7.2.2) jerarquía de los datos 4
(7.2.3) estructura FILE y punteros a archivos 7
(7.3) apertura y cierre de archivos _______________________________________________________ 7
(7.3.1) apertura 7
(7.3.2) cierre de archivos 8
(7.4) procesamiento de archivos de texto ________________________________________________ 9
(7.4.1) leer y escribir caracteres 9
(7.4.2) comprobar final de archivo 10
(7.4.3) leer y escribir strings 11
(7.4.4) volver al principio de un archivo 15
(7.5) operaciones para uso con archivos binarios_________________________________________ 15
(7.5.1) función fwrite 15
función fread 17
(7.6) uso de archivos de acceso directo __________________________________________________ 18
(7.6.1) función fseek 18
(7.6.2) función ftell 19
(7.6.3) funciones fgetpos y fsetpos 20
(7.7) ejemplos de archivos de uso frecuente _____________________________________________ 21
(7.7.1) archivos de texto delimitado 21
(7.7.2) archivos de texto con campos de anchura fija 24
(7.7.3) ficheros maestro/detalle 26
(7.7.4) formatos binarios con registros de tamaño desigual 27
(7.7.5) ficheros indexados 28
(7.7.6) otros formatos binarios de archivo 29
(7.8) índice de ilustraciones ____________________________________________________________ 30
(3)
fundamentos de programación
(Unidad 7) archivos
(7.2) introducción
(7.2.1) archivos
El problema de los datos utilizados por un programa, es qué todos los datos se
eliminan cuando el programa termina. En la mayoría de los casos se desean
utilizar datos que no desaparezcan cuando el programa finaliza (a fin de ser
usados en futuras ejecuciones del programa)
De cara a la programación de aplicaciones, un archivo no es más que una
corriente (también llamada stream) de bits o bytes que posee un final
(generalmente indicado por una marca de fin de archivo).
Para poder leer un archivo, se asocia a éste un flujo (también llamado
secuencia) que es el elemento que permite leer los datos del archivo.
En C un archivo puede ser cualquier cosa, desde un archivo de una unidad de
disco a un terminal o una impresora. Se puede asociar un flujo a un archivo
mediante la operación de apertura del archivo.
(4)
Lista de campos
Archivo
campo departamento
154
del último registro
datos de ese campo
01111111 11111111 11111111 01100101
tal cual se almacenan
Ilustración 1, Ejemplo de la jerarquía de los datos de un archivo
extendido (lo malo es que los ASCII de 8 bits son diferentes en cada
país).
• ISO 8859-1. El más usado en occidente. Se la llama codificación de
Europa Occidental. Son 8 bits con el código ASCII más los símbolos
frecuentes del inglés, español, francés, italiano o alemán entre otras
lenguas de Europa Occidental.
• Windows 1252. Windows llama ANSI a esta codificación. En realidad
se trata de un superconjunto de ISO 8859-1 que es utilizado en el
almacenamiento de texto por parte de Windows.
• Unicode. La norma de codificación que intenta unificar criterios para
hacer compatible la lectura de caracteres en cualquier idioma.
Unicode asigna un código distinto a cada símbolo, de modo que los
que van de 0 a 255 son los códigos de ISO 8859-1. De ahí en
adelante se asignan más valores a los símbolos del chino, cirílico,
japonés,…
(6)
♦ Archivos de acceso directo. Se puede acceder a cualquier dato del
archivo conociendo su posición en el mismo. Dicha posición se suele
indicar en bytes. En general los archivos binarios se utilizan mediante
acceso directo.
(7)
fundamentos de programación
(Unidad 7) archivos
modo significado
“r” Abre un archivo para lectura de archivo de textos (el archivo tiene
que existir)
“w” Crea un archivo de escritura de archivo de textos. Si el archivo ya
existe se borra el contenido que posee.
“a” Abre un archivo para adición de datos de archivo de textos
“rb” Abre un archivo para lectura de archivos binarios (el archivo tiene
que existir)
“wb” Crea un archivo para escritura de archivos binarios (si ya existe, se
descarta el contenido)
“ab” Abre un archivo para añadir datos en archivos binarios
“r+” Abre un archivo de texto para lectura/escritura en archivos de
texto. El archivo tiene que existir
“w+” Crea un archivo de texto para lectura/escritura en archivos de
texto. Si el archivo tenía datos, estos se descartan en la apertura.
“a+” Crea o abre un archivo de texto para lectura/escritura. Los datos
se escriben al final.
“r+b” Abre un archivo binario para lectura/escritura en archivos de texto
“w+b” Crea un archivo binario para lectura/escritura en archivos de
texto. Si el archivo tiene datos, éstos se pierden.
“a+b” Crea o abre un archivo binario para lectura/escritura. La escritura
se hace al final de el archivo.
(8)
pArchivo es el puntero que señala al archivo que se desea cerrar. Si devuelve el
valor cero, significa que el cierre ha sido correcto, en otro caso se devuelve un
número distinto de cero.
Esta función devuelve una constante numérica llamada EOF (definida también en
el archivo stdio.h) cuando ya se ha alcanzado el final del archivo. En otro caso
devuelve el siguiente carácter del archivo.
Ejemplo:
#include <stdio.h>
(9)
fundamentos de programación
(Unidad 7) archivos
función fputc
Es la función que permite escribir caracteres en un archivo de texto. Prototipo:
#include <stdio.h>
(10)
(7.4.3) leer y escribir strings
función fgets
Se trata de una función que permite leer textos de un archivo de texto. Su
prototipo es:
Esta función lee una cadena de caracteres del archivo asociado al puntero de
archivos pArchivo y la almacena en el puntero texto. Lee la cadena hasta que
llegue un salto de línea, o hasta que se supere la longitud indicada. La función
devuelve un puntero señalando al texto leído o un puntero nulo (NULL) si la
operación provoca un error.
Ejemplo (lectura de un archivo de texto):
#include <stdio.h>
En el listado el valor 2000 dentro de la funcón fgets tiene como único sentido,
asegurar que se llega al final de línea cada vez que lee el texto (ya que ninguna
línea del archivo tendrá más de 2000 caracteres).
En el ejemplo se utiliza una técnica de lectura de archivos, llamada lectura
adelantada, en la que antes de entrar en el bucle que controla el final de
archivo(while(¡feof(archivo)), se hace una primera lectura, de otra forma
(11)
fundamentos de programación
(Unidad 7) archivos
aparecería dos veces la última línea, ya que cuando se llega al final, fgets
devuelve la última línea de texto.
función fputs
Es equivalente a la anterior, sólo que ahora sirve para escribir strings dentro del
un archivo de texto. Prototipo:
#include <stdio.h>
#include <string.h>
función fprintf
Se trata de la función equivalente a la función printf sólo que esta permite la
escritura en archivos de texto. El formato es el mismo que el de la función
printf, sólo que se añade un parámetro al principio que es el puntero al archivo
en el que se desea escribir. La ventaja de esta instrucción es que aporta una
gran versatilidad a la hora de escribir en un archivo de texto.
(12)
Ejemplo. Imaginemos que deseamos almacenar en un archivo los datos de
nuestros empleados, por ejemplo su número de empleado (un entero), su
nombre (una cadena de texto) y su sueldo (un valor decimal). Entonces habrá
que leer esos tres datos por separado, pero al escribir lo haremos en el mismo
archivo separándolos por una marca de tabulación. El código sería:
#include <stdio.h>
pArchivo=fopen("c:\\prueba3.txt","w");
if(pArchivo!=NULL){
do{
printf("Introduzca el número de empleado: ");
scanf("%d",&n);
/*Solo seguimos si n es positivo, en otro caso
entenderemos que la lista ha terminado */
if(n>0){
printf("Introduzca el nombre del empleado: ");
scanf("%s",nombre);
printf("Introduzca el salario del empleado: ");
scanf("%lf",&salario);
fprintf(pArchivo,"%d\t%s\t%lf\n",
n,nombre,salario);
}
}while(n>0);
fclose(pArchivo);
}
}
(13)
fundamentos de programación
(Unidad 7) archivos
función fscanf
Se trata de la equivalente al scanf de lectura de datos por teclado. Funciona
igual sólo que requiere un primer parámetro que sirve para asociar la lectura a
un puntero de archivo. El resto de parámetros se manejan igual que en el caso
de scanf.
Ejemplo (lectura de los datos almacenados con fprintf, los datos están
separados por un tabulador).
#include <stdio.h>
fscanf(pArchivo,"%d\t%s\t%lf\n",&n,nombre,&salario);
printf("%d\t%s\t%lf\n",n,nombre,salario);
}
fclose(pArchivo);
}
return 0;
}
función fflush
La sintaxis de esta función es:
(14)
(7.4.4) volver al principio de un archivo
La función rewind tiene este prototipo:
(15)
fundamentos de programación
(Unidad 7) archivos
typedef struct {
char nombre[25];
int edad;
}Persona;
pArchivo=fopen("datos.dat","wb");
if(pArchivo!=NULL){
do{
fflush(stdin); /* Se vacía el búfer de teclado */
printf("Introduzca el nombre de la persona: ");
gets(per[i].nombre);
if(strlen(per[i].nombre)>0){
printf("Introduzca la edad");
scanf("%d",&(per[i].edad));
fwrite(&per[i],sizeof(Persona),1,pArchivo);
i++;
}
}while(strlen(per[i].nombre)>0 && i<=24);
fclose(pArchivo);
}
else{
printf("Error en la apertura del archivo");
}
return 0;
}
(16)
La instrucción fwrite del ejemplo anterior, escribe el siguiente elemento leído,
del cual recibe su dirección, tamaño (calculado con sizeof), una indicación de
que que sólo se escribe un elemento y el archivo en el que se guarda (el archivo
asociado al puntero pArchivo).
función fread
Se trata de una función absolutamente equivalente a la anterior, sólo que en
este caso la función lee del archivo. Prototipo:
El uso de la función es el mismo que fwrite, sólo que en este caso lee del
archivo. La lectura es secuencial se lee hasta llegar al final del archivo. La
instrucción fread devuelve el número de elementos leídos, que debería coincidir
con el parámetro cuenta, de no ser así es que hubo un problema o es que se
llegó al final del archivo (el final del archivo se puede controlar con la función
feof descrita anteriormente).
Ejemplo (lectura del archivo datos.dat escrito anteriormente):
#include <stdio.h>
typedef struct {
char nombre[25];
int edad;
}Persona;
pArchivo=fopen("datos.dat","rb");
if(pArchivo!=NULL){
/* Se usa lectura adelantada, de otro modo
el último dato sale repetido */
fread(&aux,sizeof(Persona),1,pArchivo);
while(!feof(pArchivo)){
printf("Nombre: %s, Edad: %d\n",aux.nombre,
aux.edad);
fread(&aux,sizeof(Persona),1,pArchivo);
}
fclose(pArchivo);
} /* if */
(17)
fundamentos de programación
(Unidad 7) archivos
else{
printf("Error en la apertura del archivo");
}
return 0;
}
typedef struct {
char nombre[25];
int edad;
}Persona;
(18)
int main(int argc, char *argv[]){
Persona aux;
FILE *pArchivo;
pArchivo=fopen("datos.dat","rb");
if(pArchivo!=NULL){
fseek(pArchivo,3*sizeof(Persona),SEEK_SET);
fread(&aux,sizeof(Persona),1,pArchivo);
printf(“%s, %d años”,aux.nombre,aux.edad);
fclose(pArchivo);
}
return 0;
}
Por ejemplo para obtener el número de registros de un archivo habrá que dividir
el tamaño del mismo entre el tamaño en bytes de cada registro. Ejemplo:
(19)
fundamentos de programación
(Unidad 7) archivos
if(f!=NULL){
fseek(f,0,SEEK_END);
nReg=ftell(f)/sizeof(Movimiento);
printf("Nº de registros en el archivo = %d",nReg);
}
else{
printf("Error en la apertura del archivo");
}
return 0;
}
FILE *f=fopen(“prueba.bin”,”rb+”);
fpos_t posicion;
if(f!=NULL){
...... /*operaciones de lectura o de manipulación*/
fgetpos(f,&posicion); /*Captura de la posición
actual*/
... /*operaciones de lectura o manipulación */
fsetpos(f,&posicion); /*El cursor vuelve a la posición
capturada */
(20)
(7.7) ejemplos de archivos de uso frecuente
(7.7.1) archivos de texto delimitado
Se utilizan muy habitualmente. En ellos se entiende que cada registro es una
línea del archivo. Cada campo del registro se separa mediante un carácter
especial, como por ejemplo un tabulador.
Ejemplo de contenido para un archivo delimitado por tabuladores:
1 Pedro 234.430000
2 Pedro 45678.234000
3 Pedro 123848.321000
5 Javier 34120.210000
6 Alvaro 324.100000
7 Alvaro 135.600000
8 Javier 123.000000
9 Pedro -5.000000
La escritura de los datos se puede realizar con la función fprintf, por ejemplo:
fprintf(“%d\t%s\t\%lf”,numMov,nombre,saldo);
fscanf(“%d\t%s\t\%lf”,&numMov,nombre,&saldo);
AR,6,0.01
AR,7,0.01
AR,8,0.01
AR,9,0.01
AR,12,0.02
AR,15,0.03
AR,20,0.04
AR,21,0.05
BI,10,0.16
BI,20,0.34
BI,38,0.52
BI,57,0.77
fprintf(“%s,%d,%lf”,tipo,modelo,precio);
(21)
fundamentos de programación
(Unidad 7) archivos
Pero la instrucción:
fscanf(“%s,%d,%lf”,tipo,&modelo,&precio);
tokens
Este, es un texto-delimitado
delimitadores
En el diagrama anterior la frase "Este, es un texto-delimitado" se muestra la
posible composición de tokens y delimitadores del texto. Los delimitadores se
deciden a voluntad y son los caracteres que permiten separar cada token.
(22)
Ejemplo de uso:
int main(){
char texto[] = "Texto de ejemplo. Utiliza, varios delimitadores\n\n";
Para leer del archivo anterior (el delimitado con comas, el código sería):
#include <stdio.h>
#include <string.h>
#include <ctype.h>
(23)
fundamentos de programación
(Unidad 7) archivos
int main(){
FILE *pArchivo=fopen("piezas.txt","r");
char tipo[3];
char linea[2000];
int modelo;
double precio;
if(pArchivo!=NULL){
fgets(linea,2000,pArchivo);
while(!feof(pArchivo)){
extraeDatos(linea,&tipo,&modelo,&precio);
printf("%s %d %lf\n",tipo,modelo,precio);
fgets(linea,2000,pArchivo);
}
fclose(pArchivo);
}
return 0;
}
Ejemplo de archivo:
AR6 0.01
AR7 0.01
AR8 0.01
AR9 0.01
AR12 0.02
AR15 0.03
AR20 0.04
AR21 0.05
BI10 0.16
BI20 0.34
BI38 0.52
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <conio.h>
(25)
fundamentos de programación
(Unidad 7) archivos
int main(){
FILE *pArchivo=fopen("piezas.txt","r");
char tipo[3];
char linea[2000];
int modelo;
double precio;
if(pArchivo!=NULL){
fgets(linea,2000,pArchivo);
while(!feof(pArchivo)){
extraeDatos(linea,&tipo,&modelo,&precio);
printf("%s %d %lf\n",tipo,modelo,precio);
fgets(linea,2000,pArchivo);
}
fclose(pArchivo);
}
getch();
return 0;
}/*fin del main */
(26)
Teniendo estos datos en ambos ficheros, si quisiéramos sacar por ejemplo los
datos de cada cliente (nombre y apellidos por ejemplo) necesitamos usar el
campo común (código) de ambos ficheros. Así, para sacar los datos de Antonio,
recogeríamos el número de código y después leeríamos del fichero 2, sólo los
datos correspondientes a ese número.
Es un tipo de fichero muy utilizados en la realidad.
typedef struct{
char nombre[60];
int edad;
int curso;
} Alumno;
Un alumno puede tener como nombre un texto que no llegue a 60 caracteres, sin
embargo al almacenarlo en el archivo siempre ocupará 60 caracteres. Eso
provoca que el tamaño del archivo se dispare. En lugar de almacenarlo de esta
forma, el formato podría ser así:
El campo nombre ahora es de longitud variable, por eso hay un primer campo
que nos dice qué tamaño tiene este campo en cada registro. Como ejemplo de
datos:
7 Alberto 14 1
11 María Luisa 14 1
12 Juan Antonio 15 1
Los registros son de tamaño variable, como se observa con lo que el tamaño del
archivo se optimiza. Pero lo malo es que la manipulación es más compleja y hace
imposible el acceso directo a los registros (es imposible saber cuando comienza
el quinto registro).
(27)
fundamentos de programación
(Unidad 7) archivos
Para evitar el problema del acceso directo, a estos archivos se les acompaña
de un archivo de índices, el cual contiene en cada fila dónde comienza cada
registro.
Ejemplo:
(28)
Fecha
Posición en
movimiento Importe Id Cuenta Concepto
el archivo
(Clave)
12/4/2005 17:12:23 1234.21 23483484389 Nómina 0
11/4/2005 9:01:34 -234.98 43653434663 Factura del gas 230
12/4/2005 17:45:21 -12.34 23483484389 Compras 460
12/4/2005 12:23:21 987.90 43653434663 Nómina 690
11/4/2005 17:23:21 213.45 34734734734 Devolución hacienda 920
Fichero Índice:
Fecha movimiento
Inicio en bytes
(Clave)
11/4/2005 9:01:34 230
11/4/2005 17:23:21 920
12/4/2005 17:12:23 0
12/4/2005 12:23:21 690
12/4/2005 17:45:21 460
Byte nº 0 3 6
Tipo Versión
Anchura en bytes
(Siempre vale “GIF”) (”89a” o “87a”)
Byte nº 8 10 11 12 13 ?
Inform. color
Altura en bytes sobre
Ratio ...(info imagen)....
de
pantalla fondo píxel
(29)
fundamentos de programación
(Unidad 7) archivos
int main(){
FILE *pArchivo;
int ancho=0, alto=0; /*Aquí se almacena el resultado*/
pArchivo=fopen("archivo.gif","rb");
if(pArchivo!=NULL) {
/* Nos colocamos en el sexto byte, porque ahí está la
información sobre la anchura y después la altura*/
fseek(pArchivo,6,SEEK_SET);
fread(&ancho,2,1,pArchivo);
fread(&alto,2,1,pArchivo);
printf("Dimensiones: Horizontal %d, Vertical %d\n",
ancho,alto);
}
return 0;
}
(30)