Professional Documents
Culture Documents
CAPITULO 14
ARCHIVOS
Introduccin
En el captulo anterior vimos cmo organizar la informacin relativa a una
biblioteca en arreglos de estructuras o bien en arreglos paralelos. Todas las
estructuras de datos vistas hasta ahora, arreglos de una o ms dimensiones y
variavles de estructuras, se almacenan en memoria RAM. Como esta memoria es
voltil, cuando se apaga la computadora toda la informacin almacenada en ella se
borra y por consiguiente tendramos cada vez volver a ingresar toda la
informacin. Esto en impensable en situaciones reales, por ejemplo una biblioteca
que contenga 100000 libros en lugar de 20. Para evitar esto utilizaremos medios de
almacenamiento secundario: las cintas magnticas, los discos rgidos, los discos
flexibles y los discos de almacenamiento ptico son ejemplos de medios de
almacenamiento secundario.
El almacenamiento secundario tiene varias ventajas con respecto a la
memoria RAM: no requieren el suministro continuo de energa elctrica para
conservar la informacin; se puede almacenar ms informacin en estos medios de
la que normalmente puede almacenarse en RAM y es ms econmica. Tales
ventajas no se logran sin dar algo a cambio: el acceso a la informacin del
almacenamiento secundario es mucho ms lento que el acceso a memoria RAM.
Como puede verse guardar la informacin en un disco u otra forma de
almacenamiento secundario tiene sus ventajas y desventajas, por ello la decisin
de qu se guarda y qu no en disco debe hacerse cuidadosamente.
Archivos
Archivos
Archivos
Apertura De Un Archivo
Para abrir un archivo se utiliza la funcin fopen() (f: file, archivo en ingls;
open: abrir). Esta funcin sirve para asociar la variable puntero a archivo, que
llamaremos archivo lgico, con un archivo en disco u otro medio externo, que
llamaremos archivo fsico. Adems informa el tipo de archivo y el modo de
apertura. El prototipo de fopen() es:
FILE *fopen(char nombrearchivo[], char modo[]);
donde nombrearchivo[] es una cadena de caracteres, constante o variable, que
formen un nombre archivo vlido para el sistema operativo, y puede incluir la
especificacin de una va de acceso y modo es una cadena que indica el tipo de
archivo (de texto o binario) y si el archivo se va a usar slo de lectura, slo de
escritura o para ambas cosas. El valor de retorno de fopen() es un puntero a
archivo. Si tiene lugar un error cuando se intenta abrir el archivo, fopen() retorna
el valor NULL (un puntero nulo).
Si quisiramos leer desde un archivo de nombre mensaje.txt localizado en
el mismo directorio que el programa, escribimos:
arch = fopen(mensaje.dat, rt);
donde rt indica que mensaje.txt se va abrir como un archivo de texto slo de
lectura (r: reading, lectura en ingls y t:text).
Si queremos asociar a la variable puntero a archivo fp a un archivo de
nombre ventas.dat que est en el directorio prueba de un disco flexible,
escribimos:
fp = fopen(A:\prueba\ventas.dat, rt);
El siguiente programa define, en primer lugar, una variable puntero a archivo
de nombre p y luego asocia este puntero con un archivo de texto de nombre
prueba.txt. Si el archivo no existe ocurrir un error y fopen() retorna NULL.
#include <stdio.h>
#include <conio.h>
main()
{ FILE *p;
p = fopen("prueba.txt","rt");
if (p == NULL)
printf("El archivo no existe");
else
printf("El archivo existe");
}
4
Archivos
Archivos
Archivos
Archivos
Archivos
Martinez Oscar
Italia 2345
Florida
Buenos Aires
1635
Archivos
10
Archivos
registro
0
registro
1
registro
2
SEX
O
DEPARTEMENTO CATEGORA
30
25
40
/*
Este esquema es slo una representacin lgica del archivo. El archivo es
simplemente una secuencia de bytes. Fsicamente este archivo es:
000000000001110100011000000000000001100100001........
Los primeros 16 bits representan al nmero 30, los siguiente 8 a la letra A,
los prximos 16 al nmero 6, a as sucesivamente.
11
Archivos
Archivo Comisin 1
Archivo Comisin 2
Archivos
3.
4.
5.
6.
Creacin
Actualizacin, incluyendo
insercin de registros
modificacin de uno o ms campos
eliminacin de registros
Recuperacin, incluyendo
consulta
generacin de reportes
Ordenacin
Fusin
Mantenimiento
estructuracin
compactacin
Creacin De Un Archivo
La creacin de un archivo consiste en la asignacin de un lugar en el disco y
eventualmente en la carga de la informacin. La carga de la informacin puede
hacerse interactivamente o bien desde otro archivo.
Actualizacin De Un Archivo
Consiste en la insercin de nuevos registros o en la eliminacin de registros
que no se utilizan ms. Tambin puede ocurrir que debamos modificar uno o ms
datos del registro.
Recuperacin De La Informacin
Existen bsicamente dos clases de recuperacin de la informacin: consulta
y generacin de reportes. La consulta, generalmente, produce poca informacin y
es interactiva, por ejemplo el alumno Gonzlez pregunta qu nota obtuvo en el
primer examen. En cambio, el reporte puede generar muchas pginas de salida de
informacin como obtener un listado de todos los alumnos que no han aprobado el
segundo examen.
13
Archivos
Ordenacin
Generalmente los archivos se crean con algn criterio de ordenacin, en el
ejemplo que estamos tratando puede ser la matrcula, pero en cualquier momento
podemos necesitar el archivo ordenado por algn otro campo. Ac, como veremos
ms adelante, debemos considerar el caso de archivos chicos y archivos grandes.
Fusin
La fusin o intercalacin de archivos es otra tarea frecuente en los sistemas
de procesamiento de datos. Supongamos un banco que decide cerrar una de sus
sucursales, entonces todos los clientes de sta debern pasar a otra sucursal y por
lo tanto los archivos de ambas sucursales debern fusionarse.
Mantenimiento De Archivos
Cambios hechos sobre archivos para mejorar la eficiencia de los programas
que los utilizan son conocidos como actividades de mantenimiento. Dentro de este
tipo de operaciones debemos considerar la modificacin de la estructura de los
registros y la compactacin. Supongamos que para cada alumnos deseamos
agregar una tercer nota, deberemos entonces recorrer todo el archivo modificando
la estructura de cada registro. La compactacin consiste en eliminar fsicamente
aquellos registros que han sido dados de baja. Generalmente cuando se elimina un
registro en realidad se lo marca como anulado. Si hay muchas bajas y no se realiza
compactacin el archivo tendr un porcentaje elevado de registros que se
encuentran en desuso.
14
Archivos
La Funcin fwrite()
El prototipo de fwrite() es:
unsigned fwrite(void *p, int cant_bytes, int contador, FILE *arch);
donde p es un puntero a void, cant_bytes y contador son enteros y arch es un
puntero a archivo. La funcin fwrite() transfiere contador*cant_bytes bytes desde
la direccin de memoria indicada por p al archivo asociado a arch.
El siguiente programa guarda el nmero 5 en el archivo binario numero.dat.
#include <stdio.h>
#include <conio.h>
main()
{ FILE * salida;
int i;
salida = fopen("numero.dat","wb");
i = 5;
fwrite(&i, 2, 1, salida);
fclose(salida);
}
La sentencia:
fwrite(&i, 2, 1, salida);
transfiere dos bytes (tamao de un entero) desde la direccin de memoria &i al
archivo lgico salida.
A continuacin se muestra otro ejemplo con fwrite().
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
void generar_aleat(float a[], int n);
main()
{ FILE * f;
float a[10];
f = fopen("aleatorios","wb");
generar_aleat(a, 10);
fwrite(a, 4, 10, f);
fclose(f);
15
Archivos
}
void generar_aleat(float a[], int n)
{ int i;
randomize();
for (i = 0; i < n; i++)
a[i] = random(1000);
}
La sentencia:
fwrite(a, 4, 10, f);
transfiere 40 bytes desde la variable a al archivo asociado con f. Notar que en el
primer ejemplo usamos &i y en el segundo simplemente a por qu?.
C proporciona la funcin sizeof() que es muy til pues nos evita recordar el
tamao de los enteros, float, double, etc. Para invocarla, escibimos:
sizeof(tipo_de_datos);
donde tipo_de_datos es cualquier tipo permitido, incluso un tipo struct, y el
valor de retorno es la cantidad de bytes que ocupa ese tipo.
Valor de retorno
sizeof(int);
sizeof(double);
struct emp
{ int edad;
char sexo;
int depto;
char categoria;
};
sizeof(emp);
En el siguiente ejemplo vamos a crear un archivo y alamacenar en l, el
nmero de matrcula, el apellido y nombre y la calificacin del primer examen de
los alumnos correspondientees a una comisin. Prever que otros programas puedan
ingresar las calificaciones de otros dos examenes; dar de baja a registros que
16
Archivos
corresponden a alumnos que han abandonado el curso o bien dar de alta a nuevos
alumnos.
En primer lugar debemos definir la estrucutura reg como sigue:
struct reg
{ char matricula[5];
char apel_nom[30];
int calif_1;
int calif_2;
int calif_3;
char borrado;
};
<stdio.h>
<conio.h>
<string.h>
<entrada.h>
<stdlib.h>
FILE *abrir();
void altas (FILE * arch);
int valido1(char c);
struct reg
{ char matricula[5];
char apel_nom[30];
int calif_1;
int calif_2;
int calif_3;
char borrado;
};
main()
{ FILE * arch;
arch = abrir();
altas(arch);
fclose(arch);
}
void altas (FILE * arch)
{ struct reg alumno;
char nota[3];
clrscr();
printf("Matricula: ");
gotoxy(20,1);
getstr(alumno.matricula, 4, 4, valido1);
while (strcmp(alumno.matricula, "0000") != 0)
17
Archivos
gotoxy(1,3);
printf("Apellido y Nombre: ");
gotoxy(1,5);
printf("Calificacion 1: ");
gotoxy(20, 3);
gets(alumno.apel_nom);
gotoxy(20,5);
getstr(nota, 1, 2, valido1);
alumno.calif_1 = atoi(nota);
alumno.borrado = N;
fwrite(&alumno,sizeof(struct reg),1,arch);
clrscr();
printf("Matricula: ");
gotoxy(20,1);
getstr(alumno.matricula, 4, 4, valido1);
}
int valido1(char c)
{
return ( c >= '0') && (c <= '9');
}
FILE *abrir()
{ FILE *pf;
char nom_arch[15];
clrscr();
printf("Ingresar nombre del archivo: ");
gets(nom_arch);
pf = fopen(nom_arch,"r+b");
if (pf == NULL)
pf = fopen(nom_arch,"wb");
return pf;
}
alumno
matricula
nom_arch
apel_nom
calif_1
calif_2
calif_3
borrado
18
Archivos
arch
alumno
matricula
nom_arch
comis_1
apel_nom
calif_1
calif_2
calif_3
borrado
alumno
matricula
nom_arch
comis_1
apel_nom
calif_1
calif_2
calif_3
borrado
Disco
comis_1 (0 bytes)
alumno
7856
nom_arch
comis_1
matricula apel_nom
calif_1
calif_2
calif_3
borrado
Disco
comis_1 (0 bytes)
alumno
7856
nom_arch
Gonzlez Alberto
matricula apel_nom
5
calif_1
19
N
calif_2
calif_3
borrado
comis_1
Archivos
Disco
comis_1 (0 bytes)
alumno
7856
Gonzlez Alberto
matricula apel_nom
calif_1
N
calif_2
concepto
nom_arch
comis_1
borrado
Disco
comis_1
7856 Gonzlez Alberto
alumno
7860
Gonzlez Alberto
matricula apel_nom
calif_1
N
calif_2
concepto
nom_arch
comis_1
borrado
Disco
comis_1
7856 Gonzlez Alberto 5
Como el valor ledo es diferente de cero se ejecuta el ciclo while que solicita
un nuevo nombre y otra calificacin que se leee en alumno.nombre y en
alumno.calif_1 respectivamente y se asigna N a alumno.borrado.
Memoria RAM
20
Archivos
arch
alumno
7860
Martinez Jorge
matricula apel_nom
nom_arch
comis_1
calif_1
calif_2
concepto
borrado
Disco
comis_1
7856 Gonzlez Alberto
alumno
7860
Martinez Jorge
matricula apel_nom
nom_arch
comis_1
calif_1
calif_2
concepto
borrado
Disco
comis_1
7856 Gonzlez Alberto
Ejercicios
Ejercicio 14.#
Escribir un pogrma para construir un archivo de 10 nmeros enteros que se
ingresan por teclado.
Escribir funciones para:
a. crear un archivo de Clientes, donde cada cliente consta de la siguiente
informacin: nombre, calle, nmero, localidad y provincia, cuit, saldo.
b. cargar datos en el archivo anterior.
Crear y cargar datos en un archivo de alumnos, cada registro debe contener la
siguiente informacin: nombre, direccin, edad y fecha.
21
Archivos
La Funcin fread()
Un archivo binario no puede ser visualizado con un editor de texto. Por
ejemplo, el si abrimos el archivo aleatorios, construido anterioemente, con
NOTEPAD o cualquier otro editor veriamos algo similar alo siguiente:
2222C22C228D2222YD2222C22D2222C22@ D2222C22sD
#include <stdio.h>
#include <conio.h>
main()
{ FILE * aleat;
22
Archivos
float a[10];
int i;
aleat = fopen("aleatorios","rb");
fread(a, 4, 10, aleat);
fclose(aleat);
clrscr();
for (i = 0; i < 10; i++)
printf("\n%7.2f",a[i]);
getch();
}
R1
R2
arch
R3
valor de eof(arch)
23
Rn
/*
Archivos
R2
arch
R3
Rn
/*
Rn
/*
Rn
/*
valor de eof(arch)
R2
arch
R3
valor de eof(arch)
R2
arch
R3
valor de eof(arch)
La ejecucuin del programa anterior muestra una salida por pantalla similar a:
Matricula
7896
7860
6560
7890
8990
7555
Apellido y Nombre
Gonzalez Alberto
Martinez Jorge
Smith Roberto
Silveira Sebastian
Rizzo Juan
Rodriguez Pedro
24
Calificacion 1
5
8
6
3
2
5
Archivos
Ejercicios
Escribir un algoritmo que busque en el archivo de enteros construido en el ejercicio
14#, el entero ms pequeo y ms grande del archivo.
visualizar el archivo construido en ejercicio 14.#
Visualizar el archivo creado en 14#
La Funcin fseek()
En este ltimo ejemplo hemos procesado al archivo secuencialmente; lemos
el primer registro y mostramos alunos campos por pantalla, luego lemos el
segundo registro y as sucesivamente hasta encontrar el fin del archivo. Sin
embargo en muchas aplicaciones es necesario acceder a la informacin de un
determinado registro. La funcin fseek() nos permite acceder directamente a
cualquier posicin del archivo, sin necesidad de leer toda la informacin anterior.
Su prototipo es:
int fseek(FILE *arch, long num_bytes, int origen);
Donde arch es un puntero a archivo, num_bytes es un entero largo y origen es un
entero cuyos valores pueden ser 0, 1 2. El valor de num_bytes es la cantidad de
bytes a partir de origen que debe tomarse como la nueva posicin actual. Los
valores de origen tiene el siguiente significado.
0:
1:
2:
Archivos
fclose(aleat);
}
26
Archivos
Apellido y Nombre
Silveira Sebastian
Rizzo Juan
Total de inscriptos: 6
Total de insuficientes: 2
Porcentaje de insuficientes: 33.33
Oprimir una tecla para continuar...
Consulta de un registro
Supongamos que deseamos consultar la informacin de un alumno
conociendo su matrcula. Como el archivo no est ordenado debemos realizar una
bsqueda secuencial, similar a la que realizbamos cuando la informacin est
almacenada en arreglos. Posicionar al puntero de archivo al incio del mismo;
acceder al primer registro, si el campo matrcula es igual a la matrcula dada
mostramos la informacin, sino accedemos al segundo registro; se contina as
hasta que se encuentre la matrcula o se haya accedido al final del archivo. La
funcin buscar() busca la matricula en el archivo, si la encuentra retorna el
nmero de registro correspondiente y si no la encuentra retorna -1.
void consulta (FILE * arch)
{ struct reg alumno;
char mat_a_buscar[5];
int k;
clrscr();
27
Archivos
}
}
28
Archivos
Calificacion 1: 8
Calificacion 2: -4865
Calificacion 3: -18945
Oprima una tecla para continuar...
Ejercicios
Utilizando el archivo creado en 14#
c. consultar un cliente.
b. Construir funciones que permitan responder a las siguientes preguntas:
a. Cuales clientes tienen saldo inferior a 0?
b. Cuantos clientes viven en la provincia de Crdoba?
c. Listar los clientes cuyo nombre comienza con 'M'?
d. Cual es el cliente con saldo mayor?
A pertir del archivo de alumnos creado en ejercicio 14#, escibir funciones para:
construir un nuevo archivo que contenga slo los nombres y edad
obtener un listado con el nombre y direccin de cada alumno cuyos nombres
comiencen con las letras A, B o C y hayan nacido en el mes de mayo.
Algoritmos Para Actualizar Archivos
Las tres operaciones de actalizacin de archivos son:
altas: ingreso de nuevos registros
bajas: eliminacin de registros que no se necesitan ms
modificacin: modificar la informacin de uno o ms campos uno ms
registros
29
Archivos
Altas
Como hemos dicho al principio del captulo siempre es conveniente que
haya un dato, que se denomuina clave, que identifique en forma biunvoca al
registro. En el ejemplo que estmos tratando este dato pueder ser la matrcula, ya
que no hay dos alumnos con la misma matrcula.
Para realizar un alta posteriormente a haber creado el archivo e ingresado
algunos datos, debemos:
solcitar la clave (en este ejemplo la matrcula);
buscar la matricula en el archivo;
si la matrcula ya existe;
emitir un mensaje de error;
sino
solictar los datos al usuario;
grabarlos en el archivo;
La funcin altas() descripta anteriormente permite el ingreso de datos en un
archivo vaco. A continuacin la funcin que se describe puede usarse si el archivo
est vaco o si ya contiene algunos datos.
void altas (FILE * arch)
{ struct reg alumno;
char nota[3];
int k;
clrscr();
printf("Ingresar matricula: ");
getstr(alumno.matricula, 4,4, valido1);
while (strcmp(alumno.matricula,"0000") != 0)
{
k = buscar(alumno.matricula, arch);
if ( k == -1)
{
gotoxy(1,3);
printf("Apellido y Nombre: ");
gotoxy(1,5);
printf("Calificacion 1: ");
gotoxy(20, 3);
gets(alumno.apel_nom);
gotoxy(20,5);
getstr(nota, 1, 2, valido1);
alumno.calif_1 = atoi(nota);
alumno.borrado = 'N';
fseek(arch,0,2);
fwrite(&alumno,sizeof(struct reg),1,arch);
}
else
{ printf("\n\nLa matricula ya existe");
getch();
30
Archivos
}
clrscr();
printf("Ingresar matricula: ");
getstr(alumno.matricula, 4,4, valido1);
Bajas
Otra de las operaciones frecuentes en el manejo de archivos es la
eliminacin lgica de registros. Esta operacin consiste en marcar algn campo de
manera que indique que el registro ha sido borrado. Se puede disponer algn
campo para tal fin, como en el ejemplo, o bien considerar algn campo con un
valor ilegal, como por ejemplo, un * para nombre y apellido. Los pasos a seguir
son:
solcitar la clave (en este ejemplo la matrcula);
buscar la matricula en el archivo;
si la matrcula no existe;
emitir u n mensaje de error;
sino
marcar el campo que indica qie el registro est borrado;
void bajas (FILE * arch)
{ struct reg alumno;
int k;
clrscr();
printf("Ingresar matricula: ");
getstr(alumno.matricula, 4,4, valido1);
while (strcmp(alumno.matricula,"0000") != 0)
{
k = buscar(alumno.matricula, arch);
if ( k != -1)
{ fseek(arch, k*sizeof(reg), 0);
fread(&alumno, sizeof(reg), 1, arch);
printf("Esta a punto de borrar al alumno");
printf(" %s ",alumno.apel_nom);
getch();
alumno.borrado = 'S';
fseek(arch, k*sizeof(reg), 0);
fwrite(&alumno,sizeof(struct reg),1,arch);
}
else
{ printf("\n\nLa matricula NO existe");
getch();
}
clrscr();
printf("Ingresar matricula: ");
getstr(alumno.matricula, 4,4, valido1);
}
}
31
Archivos
Modificaciones
Esta operacin es muy similar a la baja lgica. Los pasos a seguir son:
solcitar la clave (en este ejemplo la matrcula);
buscar la matricula en el archivo;
si la matrcula no existe;
emitir u n mensaje de error;
sino
solictar nuevos datos;
actualizar los campos que correspondan;
En la siguiente funcin se modifica la calificacin del segundo o tercer examen.
void modificaciones (FILE * arch, int i)
{ struct reg alumno;
int n;
char nota[3];
int k;
n = leer_nro_examen();
clrscr();
printf("Ingresar matricula: ");
getstr(alumno.matricula, 4,4, valido1);
while (strcmp(alumno.matricula,"0000") != 0)
{
k = buscar(alumno.matricula, arch);
if ( k != -1)
{ fseek(arch, k*sizeof(reg), 0);
fread(&alumno, sizeof(reg), 1, arch);
if (alumno.borrado == 'N')
{ printf ("Ingresar la calificacion del examen %d: ", n);
getstr(nota,1,2,valido1);
if (n == 2)
alumno.calif_2 = atoi(nota);
else
alumno.calif_3 = atoi(nota);
fseek(arch, k*sizeof(reg), 0);
fwrite(&alumno,sizeof(struct reg),1,arch);
}
else
{ printf("\n\nLa matricula NO existe");
getch();
}
}
else
{ printf("\n\nLa matricula NO existe");
getch();
}
32
Archivos
clrscr();
printf("Ingresar matricula: ");
getstr(alumno.matricula, 4,4, valido1);
}
int leer_nro_examen()
{ int n;
char cn[2];
clrscr();
printf("ingresar numero de examen: ");
getstr(cn,1,1,valido2);
n = atoi(cn);
return n;
}
Ejercicios
dar de alta un nuevo cliente
eliminar un cliente (un cliente se considera dado de baja si hay un * en su nombre.
dado un cliente modificar sus datos
Ttulo no se
En las secciones anteriores hemos construidos las funciones para crear y
actualizar archivos, as como las de recupracin de la informacin en forma
separada. Como hay muchas funciones comunes a todas ellas: buscar(), valido1(),
abrir(), ahora vamos a compaginarlas de manera que todas sean invocadas desde
un nico main() mediante un menu.
#include
#include
#include
#include
#include
<stdio.h>
<conio.h>
<string.h>
<entrada.h>
<stdlib.h>
FILE *abrir();
void altas (FILE * arch);
void bajas (FILE * arch);
void modificaciones (FILE * arch, int nroexamen);
void mostrar (FILE * arch);
void consulta (FILE * arch);
void informe (FILE * arch);
int valido1(char c);
int valido2(char c);
int buscar (char mat[], FILE * arch);
char menu();
33
Archivos
int leer_nro_examen();
struct reg
{ char matricula[5];
char apel_nom[30];
int calif_1;
int calif_2;
int calif_3;
char borrado;
};
void main()
{
FILE * arch;
char opcion;
int nro;
arch = abrir();
opcion = '0';
while (opcion != '7')
{
opcion = menu();
switch (opcion)
{
case '1':
altas(arch);
break;
case '2':
bajas(arch);
break;
case '3':
modificaciones(arch, nro);
break;
case '4':
mostrar(arch);
break;
case '5':
consulta(arch);
break;
case '6':
informe(arch);
break;
}
}
fclose(arch);
clrscr();
printf("Gracias por usar este programa");
getch();
}
FILE *abrir()
{
/* desarrollada en seccin anterior*/
}
void altas (FILE * arch)
34
Archivos
{
/* desarrollada en seccin anterior*/
35
Archivos
opcion = getche();
} while ((opcion < '1') || (opcion > '7'));
return opcion;
}
int leer_nro_examen()
{
/* desarrollada en seccin anterior*/
}
int valido1(char c)
{
/* desarrollada en seccin anterior*/
}
int valido2(char c)
{
return ( c >= '2') && (c <= '3');
}
Archivos
estn ordenados por alguno de sus campos, por ejemplo, matrcula podemos
intercalarlos para obtener un tercer archivo ya ordenado. La intercalacin de dos
archivos ordenados consiste en construir a partir de ellos un tercer archivo tambin
ordenado. El proceso de intercalacin se realiza, en forma similar que en el caso de
arreglos, seleccionando sucesivamente los elementos con el mnimo valor de cada
uno de los dos archivos, situndolos en el nuevo. De esta forma el nuevo archivo
tiene todos sus elementos ordenados. El algoritmo bsico de intercalacin de
archivos consiste en comparar la clave de un archivo con la del otro, pasar la
menor al nuevo archivo y avanzar en ese archivo y en el nuevo.
#include <stdio.h>
#include <conio.h>
#include <string.h>
FILE *abrir();
void fusion(FILE *f1, FILE *f2, FILE *f3);
struct reg
{ char matricula[5];
char apel_nom[30];
int calif_1;
int calif_2;
int calif_3;
char borrado;
};
main()
{ FILE *arch1, *arch2, *arch3;
arch1 = abrir();
arch2 = abrir();
arch3 = abrir();
fusion(arch1, arch2, arch3);
fclose(arch1);
fclose(arch2);
fclose(arch3);
}
FILE *abrir()
{ FILE *pf;
char archivo[15];
clrscr();
printf("Ingresar nombre del archivo: ");
gets(archivo);
pf = fopen(archivo,"r+b");
if (pf == NULL)
pf = fopen(archivo,"wb");
return pf;
}
37
Archivos
Ejercicos
Dados dos archivos, disgmos suc1 y suc 2, que contiene informacin de clienes de dos
sucursales de un banco, construir suc3 formado por los registros de suc1 seguidos por los
registros de suc2.
Algoritmos de Mantenimiento
Entre los algoritmos de mantenimiento estn aquellos que modifican la estructura
de los registros y los de compactacin.
Modificacin De Estructura
Supongamos que tenemos un archivo cuyos registros tienen una estructura reg1, y
debemos agregarle algunos campos que no haban sido previstos (por ejemplo en
el archivo de alumnos debemos agregar la calificacin del examen final), o bien
modificar el tamao de algn campo. Definimos entonces una nueva estrucutrua
38
Archivos
reg2 y dos punteror a archivos, arch1 y arch2. Tambin debemos definir dos
variables, v1 de tipo reg1 y v2 de tipo reg2, El algoritmo para modificar la
estructura consiste en abrir el archivo existente para lectura y otro nuevo para
escritura; leer cada registro del archivo viejo en v1; asignar los campos comunes
entre ambos registros a v2; escribir v2 en el archivo nuevo; cuando se llega al fin
del archivo asociado a arch1 cerrar ambos archivos.
Compactacin
Con compactacin se entiende eliminar fsicamente del archivo, aquellos registros
que han sido eliminados lgicamente. Sean la estructura reg y arch1 y arch2 de
tipo puntero a archivo, y v una variable de tipo reg. El primer archivo se abre para
lectura y el segundo para escritura; se lee de arch1 en v, si el valor de v.borrado
es N (o cualquiera sea la condicin de registro no eliminado) se ejecuta la accin
fwrite(&v, sizeof(reg), 1, arch2), en caso contrario no se efecta ninguna accin;
en ambos casos se continua con el prximo registro; finalmente se cierran ambos
archivos.
Ejercicios
1, En el archivo comis_1 se desea, para cada alumno, guardar la nora del
examen final.
2. Compactar el archivo comis_1.
Ordenacin
La ordenacin de archivos se la conoce como ordenacin externa. Si el archivo es
lo suficientemente pequeo como para que pueda caber en la memoria principal de
la computadora, los pasos a seguir son: 1) leer el archivo en un arreglo; 2) aplicar
un mtodo de ordenacin interna y 3) grabar el arreglo ordenado en el archivo.
Cuando los archivos son muy grandes, demasiado grandes para que puedan caber
en la memoria principal se debe leer porciones del archivo, aplicar un mtodo de
ordenacin interna a cada porcin y generar de esta manera subarchivos
ordenados, los cuales deben ser intercalados para obtener el archivo final.
Un mtodo de ordenacin externa consta de dos fases: ordenacin interna e
intercalacin de archivos. Como el proceso de entrada y salida es mucho ms lento
que las comparaciones en memoria, el costo de un algoritmo de ordenacin
externa no est dado por la cantidad de comparaciones y movimientos en la
memoria principal sino por la cantidad de veces que hay que recorrer el archivo.
En este ltimo punto influye el medio de almacenamiento externo en el cual est
guardado el archivo: por ejemplo, elementos guardados en una cinta magntica
pueden ser accedidos solo en manera secuencial.
39
Archivos
40
Archivos
paso 2
En este paso, A3 y A4 pasan a ser los archivos de entrada y A1 y A2 de salida.
A1: R0001 . . . R4000 R8001 . . . R9000
A2: R4001 . . . R8000
paso 3
Nuevamente A1 y A2 son de entrada y A3 y A4 de salida.
A3: R0001 . . . R8000
A4: R8001 . . . R9000
paso 4
A1: R0001 . . . R9000
fase de intercalacin
paso 1
A4: R0001 . . . R3000
41
Archivos
paso 2
A1: R0001 . . . R9000
Vemos que para P=2 se necesitaron cuatro pasos de intercalacin, mientras que
para P=3 slo han hecho falta dos. La cantidad de pasos de intercalacin tambin
depende por supuesto de la cantidad de elementos que pueden caber
simultneamente en la memoria principal. Si el archivo es de tamao N y en
memoria se pueden almacenar hasta M registros simultneamente, en la fase de
ordenamiento se construirn S = [N/M] subarchivos ordenados (La notacin [x]
indica el menor entero mayor o igual que x). A mayor S, o sea a menor M, y menor
grado de intercalacin mayor es la cantidad de pasos en la fase de intercalacin y
por consiguiente el proceso ser ms lento.
Durante cada paso de intercalacin el nmero de subarchivos que se obtienen es
aproximadamente el nmero de subarchivos del paso anterior dividido el grado de
la intercalacin (P). Adems, en cada paso casi todos los subarchivos ordenados se
alargan por un factor igual al grado de la intercalacin. Si S es de la forma P k, el
nmero de subarchivos de salida de cada paso de intercalacin es exactamente el
nmero de subarchivos de entrada al paso dividido P. Cada subarchivo de salida es
P veces de largo de cada subarchivo de entrada. Si la fase de ordenamiento interno
produce S subarchivos para ser intercalados, entonces una intercalacin
balanceada, requerir O(logPS) pasos de intercalacin.
Cortes De Control
Supongamos que disponemos de un archivo cuyos campos son: nmero de cliente,
nmero de factura e importe de la factura. Es obvio que el mismo nmero de
cliente podr aparecer varias veces en el archivo, en realidad aparecer tantas
veces como facturas tenga. Sabiendo que el archivo est ordenado por nmero de
cliente, queremos construir a partir de l otro archivo que tenga slo un registro
por cada cliente. Los campos de los registros de este ltimo archivo son nmero de
cliente e importe total.
El archivo est formado por grupos de registros que tienen el mismo valor de la
clave (en este caso mismo nmero de cliente), y cada vez que haya un cambio en
el valor de la clave debemos grabar un registro en el archivo nuevo.
42
Archivos
Archivo Existente
cliente
02
02
02
05
06
06
*
factura
345
678
789
344
348
750
Archivo Nuevo
importe
820.30
345.00
200.50
1000.00
522.50
200.00
cliente
02
05
06
*
importe_total
1365.80
1000.00
722.50
43
Archivos
strcpy(cliente_ant, v.cliente);
while (!feof(f) && (strcmp (v.cliente, cliente_ant) == 0))
{
v1.importe_total = v1.importe_total + v.importe;
fread(&v, sizeof(reg_1), 1, f);
}
strcpy(v1.cliente, cliente_ant);
fwrite(&v1, sizeof(reg_2), 1, f1);
}
Observar que hay una estructura while para recorrer todo el archivo y otra para
recorrer cada grupo de clientes. Los algoritmos de cortes de control se usan muy
frecuentemente en la programacin de sistemas comerciales, sobre todo en salida
impresa. Generalmente cada vez que se procesa un grupo se requiere un subtotal y
al final de todo el proceso un total general. Supongamos que del archivo anterior
queremos obtener el siguiente listado.
DETALLE DE VENTAS
Cliente
Factura
Importe
02
345
678
789
820.30
345.00
200.50
TOTAL CLIENTE 02
1345.80
05
344
TOTAL CLIENTE 05
1000.00
1000.00
06
348
750
TOTAL CLIENTE 06
522.50
200.00
722.50
TOTAL VENDIDO
2068.30
#include <stdio.h>
#include <conio.h>
#include <string.h>
FILE *abrir();
void listararch(FILE *f);
struct reg_1
{
char cliente[3];
char factura[4];
44
Archivos
double importe;
};
main()
{ FILE *f;
f = abrir();
listararch(f);
fclose(f);
}
void listararch(FILE *f)
{ struct reg_1 v;
char cliente_ant[3];
double total_cliente;
double total;
printf("Clientes
Importe");
total = 0;
fread(&v, sizeof(reg_1), 1,f);
while(!feof(f))
{ total_cliente = 0;
strcpy(cliente_ant, v.cliente);
printf("%s", v.cliente);
while (!feof(f) && (strcmp(v.cliente, cliente_ant) == 0))
{
printf("\n%s
%f",v.factura, v.importe);
total_cliente = total_cliente + v.importe;
fread(&v, sizeof(reg_1), 1,f);
}
printf ("\nTotal cliente %s
%f", cliente_ant,
total_cliente);
total = total + total_cliente;
}
printf("\nTotal vendido
", total);
}
Todos los algoritmos para generar listados con cortes de control tienen una forma
similar. Si los registros tuvieran adems un campo vendedor y el archivo estuviera
ordenado por vendedor y por cada vendedor por cliente, podramos obtener un
corte por vendedor y otro por cliente. Deberamos agregar una variable
total_vendedor (para totalizar las ventas de cada vendedor) y otra vendedor_ant
(para guardar el cdigo del vendedor anterior).
Para poder hacer cortes de control como el enunciado el archivo tiene que estar
ordenado de la siguiente forma :
Clave 3
Clave 2
Clave 1
Archivo
45
Archivos
Dentro del archivo se repite cada valor de la primer clave, a su vez para valores
iguales de la primer clave, se repiten valores de la clave 2, dentro de la clave 2 se
repiten valores de la clave 3 y as siguiendo. Un algoritmo para hacer tantos cortes
de control como claves haya, tiene el siguiente formato general:
acciones 0.a;
leer primer registro;
while (no fin del archivo)
{
acciones 1.a;
while ((no fin del archivo) y (clave1 igual clave1_anterior))
{
acciones 2.a;
while ((no fin de archivo) y (clave1 igual clave1_anterior) y (clave2 igual clave2_anterior))
{ .
.
.
while ((no fin de archivo) y (clave1 igual clave1_anterior) y (clave2 igual clave2 _anterior) y .....
{
procesar registro;
leer prximo registro;
.
.
}.
}
aciones 2.b;
}
acciones 1.b;
}
acciones 0.b
Observar que la cantidad de ciclos while es una ms que la cantidad de claves. Las
acciones 0.a, generalmente imprimen un ttulo y dan valores iniciales a las
variables que calculan totales de todo el archivo. Las acciones 1.a, 2.a, etc. dan
valores iniciales a los subtotales de la clave 1, clave 2 , etc respectivamente y
guardan el valor anterior de la clave. Las acciones del ciclo ms interno son
procesar el registro y leer prximo registro. Las acciones 1.b, 2.b etc., imprimen
los subtotales de la clave respectiva e incrementan los subtotales de un nivel ms
externo. Finalmente las aciones 0.b imprime los totales generales.
46
Archivos
47
Archivos
Archivo ndice
registro
matricula
apel_nom
calif_1
calif_2
concepto
borrado
matricula
registro
5678
5233
5345
5345
5787
5567
5233
5568
5567
5678
5890
5787
5789
5789
5568
5890
48
Archivos
49
Archivos
Si debemos obtener un listado por un campo que no es la clave del archivo ndice,
por ejemplo por nombre y apellido, debemos:
1. a partir del archivo de datos construir un arreglo INDICE que contenga los
valores de la nueva clave y el registro que le corresponde en el archivo de datos
2. ordenar el arreglo INDICE
3. recorrer el arreglo y obtener la informacin del registro del archivo de datos
indicado en el ndice
ndices Demasiados Grandes Para Ser Almacenados En Memoria
Las tcnicas analizadas y, por desgracia, muchas de las ventajas que presentan,
estn sujetos a la suposicin de que el archivo de ndices es lo suficientemente
pequeo para cargase por completo en memoria. Cuando el ndice es demasiado
grande para poder almacenarse en la memoria principal, se deben usar tcnicas
para crear ndices que escapan al mbito de este texto.
Ejercicio adicionales
Agregar de archivos de text
1 y 7 de cranwell
java 10.1, 10.2, 10.3
50