Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
MÓDULO I .........................................................................................................................................2
Introducción ....................................................................................................................................................................................... 3
Archivos .............................................................................................................................................................................................. 3
¿Qué son los archivos?................................................................................................................................................................. 3
¿Para qué uso un archivo?........................................................................................................................................................... 3
Modo de Acceso................................................................................................................................................................................ 4
Apareo de Archivos........................................................................................................................................................................ 16
Autoevaluación................................................................................................................................................................................ 22
Elaboración
Carlos Bruschetti
Nelson Ciffoni
Este material pertenece a la materia Programación II, de la Carrera de Analista de Sistemas de Computación del
INSTITUTO DE TECNOLOGÍA ORT.
Todos los derechos reservados. No esta permitida la reproducción total o parcial de este apunte, ni su tratamiento informático, ni
la transmisión de ninguna forma o por cualquier medio, ya sea electrónico, mecánico, por fotocopia, por registro u otros métodos,
sin el permiso previo de los titulares.
1ra edición Diciembre de 2007.
MÓDULO I
Introducción y orientaciones para el estudio
Objetivos
Pretendemos que al finalizar de estudiar esta Unidad, el alumno logre:
Contenidos
Conceptualizaciones centrales
Bibliografía
Referencia de material bibliográfico recomendado
Actividades
Usted debe tener presente que los contenidos presentados en el módulo no ahondan
profundamente en el tema, sino que pretenden ser un recurso motivador, para que a
través de la lectura del material, la bibliografía sugerida, y el desarrollo de las
actividades propuestas alcance los objetivos planteados en el presente módulo.
Cada módulo constituye una guía cuya finalidad es facilitar su aprendizaje.
Introducción
En este módulo vamos a trabajar con archivos. Qué es un archivo y para qué sirve. Cuáles son sus
usos más corrientes. Mencionaremos los distintos tipos de organización de archivos y nos
centraremos en los archivos de organización secuencial.
También revisaremos las operaciones básicas sobre archivos, el tema del procesamiento de datos
y la técnica de programación llamada corte de control. Por último analizaremos el proceso de
apareo de archivos secuenciales y desarrollaremos una estrategia de solución.
Archivos
Estas son algunas preguntas que nos hacemos cuando comenzamos a abordar el tema del manejo
de archivos.
A su vez un registro está formado por campos y constituye una unidad de información (referida por
ejemplo a un cliente, a un alumno, etc.). Estos campos son la unidad mínima de información del
registro. Estos campos se diferencian por el significado o sentido dado a cada uno.
Si el dato correspondiente un campo de un registro no toma el mismo valor para registros distintos
(por ejemplo el N° de matrícula en un archivo que contiene los alumnos de un determinado curso),
diremos que la factibilidad es 0 o 1 para el N° de matrícula. Esto significa que un N° de matrícula
dado puede aparecer a los sumo en un registro del archivo.
Hablamos de factibilidad 0/N para un campo, si en el archivo puede haber hasta N registros con el
mismo valor para ese campo. Por ejemplo el campo Nota para un archivo de alumnos de un curso
tiene factibilidad 0/N.
Organización de Archivos
El término organización de archivos se aplica a la forma en que se estructuran los registros sobre
el soporte magnético (disco, cinta,..) durante su grabación.
Podemos hacer una breve enumeración de las formas básicas de organización de archivos:
secuencial, relativa y secuencial indexada.
En la organización secuencial los registros se van grabando unos a continuación de los otros, en el
orden que se van dando de alta, mientras que en la organización relativa los registros se graban en
las posiciones que les corresponda según el valor que guarden en el campo clave.
El campo clave permite identificar unívocamente al registro. Ejemplos de campos clave son el DNI
para un archivo de personas, el código para archivos de productos o clientes, la matrícula para
archivos de alumnos.
En la organización secuencial indexada los registros se graban inicialmente en forma secuencial, y
además se utilizan tablas que permiten localizar un registro de acuerdo a su clave; además se
utilizan espacios de almacenamiento para guardar registros que se agregan y no pueden ubicarse
secuencialmente.
La forma en que se organiza un archivo determina el modo de acceso al mismo.
Modo de Acceso
El modo de acceso se refiere al procedimiento que se debe seguir para situarse en un registro
determinado para realizar una operación de lectura o grabación del mismo.
El modo de acceso puede ser secuencial o directo. En el modo de acceso secuencial para llegar a
un registro es necesario pasar por todos los anteriores, mientras que en el modo de acceso directo
se puede llegar directamente a un registro conociendo únicamente el valor del campo clave.
El modo de acceso directo se puede llevar a cabo de varias formas:
1. La posición que ocupa el registro dentro del fichero coincide con el contenido de la clave.
2. Calculando la posición que ocupa el registro en el fichero mediante una transformación del
contenido del campo clave (acceso aleatorio - Hashing).
3. Mediante el uso de tablas de índices. La localización de un registro se hace buscando en la
tabla de índices el valor del campo clave y obtenemos la posición en que está grabado el
registro dentro del fichero (acceso indexado - Keyed).
Para decidir cuál es la mejor organización hay distintos criterios a tener en cuenta: rápido acceso,
fácil actualización, economía de almacenamiento, fácil mantenimiento.
Archivos Secuenciales
La organización secuencial es la forma más simple de almacenamiento de información en un
medio magnético. Los registros están organizados de manera secuencial, es decir uno detrás del
otro y con una marca a continuación del último que indica el final del archivo. Esta marca se la
conoce con el nombre de End Of File (EOF).
La lectura se realiza desde el primer registro, pasando por cada uno de los restantes hasta llegar al
final, sin posibilidad de retroceder en el recorrido, o de saltear aleatoriamente algún registro.
Programación 2 / Módulo I Pág. 4
INSTITUTO DE TECNOLOGIA O.R.T.
Instituto incorporado a la enseñanza Oficial (A-763)
Los archivos de organización secuencial se utilizan típicamente para el procesamiento de datos por
lotes, o procesamiento batch, donde todos los registros deberán ser procesados. También suelen
utilizarse en procesos donde se debe almacenar la información a medida que se recibe para que
posteriormente otro programa la analice, es por ejemplo el caso de los archivos de log donde se
guarda cronológicamente información acerca de alguna actividad.
Antes de comenzar a hablar de estas variables, vamos a hacer una pequeña referencia al
concepto de puntero; más adelante lo profundizaremos.
¿Qué es un puntero? Un puntero (o apuntador) es una variable que hace referencia a una región
de memoria; en otras palabras es una variable cuyo contenido es una dirección de memoria.
En el caso de lectura y grabación de archivos, decimos que contamos con dos variables. La
primera de ellas es un puntero que indica la posición en el medio magnético donde se va a realizar
la operación de lectura o de escritura. O sea, este puntero indica dónde se encuentra el próximo
registro a leer, en el caso en que estemos leyendo datos del archivo, o dónde se grabará el
siguiente registro, en el caso que estemos escribiendo datos.
Este puntero es la variable que relaciona la ubicación física del archivo (en el medio magnético),
con el nombre lógico con el que se identifica el archivo en el programa. Cuando el programa hace
referencia al nombre lógico, el sistema interpreta esta asociación y sabe el lugar físico del
dispositivo magnético donde debe leer o grabar.
La otra variable deberá ser una estructura que almacenará un registro del archivo. En el caso de
leer datos, esta variable recibirá el registro que acabamos de leer y en el caso de escribir,
debemos asignarle los datos que queremos guardar en el archivo.
Abrir archivo, Cerrar archivo, Grabar registro, Leer registro, Fin de archivo, Borrar registro (no se
usa en archivos secuenciales).
A continuación comentamos y desarrollamos estas operaciones; los tipos de dato usados no están
declarados en C++ aunque sus nombres son suficientemente “explicativos”, dejamos al lector esta
tarea.
Programación 2 / Módulo I Pág. 5
INSTITUTO DE TECNOLOGIA O.R.T.
Instituto incorporado a la enseñanza Oficial (A-763)
Abrir archivo
Ubicación indica el nombre físico del archivo (el nombre que tiene en el medio magnético).
TipoApertura indica en qué forma se va a abrir este archivo. Si vamos a abrir el archivo en modo
“lectura” , debemos indicar si la lectura se hará sobre un archivo de texto (rt, read text), o sobre un
archivo binario (rb, read binary).
PudeAbrir es una variable booleana, que retornará TRUE si fue posible abrir el archivo, o FALSE
en el caso de no poder abrirlo. Generalmente, los casos en que falla la apertura del archivo, es
porque no se encontró el archivo en el lugar físico que se indicó.
Nota: En esta asignatura, y para simplificar los diagramas asumiremos que siempre es posible abrir
el archivo, dejando para la práctica en máquina este control.
void AbrirArchivoDatos (srt40 ubicacion, str2 tipoApertura, File * &ArchivoDatos, bool &pudeAbrir)
{
ArchivoDatos = fopen (ubicacion, tipoApertura);
if (ArchivoDatos == NULL)
{
cout << "No se pudo Abrir el Archivo de Datos\n";
pudeAbrir = FALSE;
}
else
{
pudeAbrir = TRUE;
}
}
En el caso que abramos un archivo para grabar datos, la variable puntero ArchivoDatos recibirá la
información del lugar donde se grabará el próximo registro y creará una entrada en el dispositivo
magnético para el nuevo archivo, con el nombre pasado en el parámetro ubicacion.
El parámetro tipoApertura ahora indica si se grabará un archivo de texto (wt) o un archivo binario
(wb).
Generalmente, los casos en que falla la apertura de un archivo, es porque no encontró el archivo
en el lugar físico indicado, o porque el dispositivo magnético se encontraba protegido contra
escritura.
El desarrollo del procedimiento y la llamada en el diagrama son los mismos que para lectura.
ATENCIÓN: Cuando se abre un archivo para escritura, en el caso que el archivo ya exista, se
reemplazará por el nuevo, perdiendo el anterior.
Esto se puede implementar con una variable booleana que devolverá TRUE en el caso que
encuentre la marca de EOF, o FALSE en caso contrario.
En lenguaje C++ contamos con una función llamada feof que evalua la condición de fin de archivo,
y devuelve 0 si está sobre la marca de fin de archivo y 1 si no lo está.
int feof(ArchivoDatos)
Leer un registro
void LeerArchivoDatos (FILE * &aDatos, ty_reg &sRegDatos, bool &bFin)
sRegDatos variable con la estructura del registro del archivo, es el patrón para leer el archivo. En
esta variable el procedimiento de lectura entrega el registro leído.
bfin indica si el archivo llegó al final, o sea, si encontró la marca de EOF (TRUE), o no.(FALSE)
Grabar un registro
void GrabarRegistroDatos (FILE * &aDatos, ty_reg sRegDatos)
sRegDatos variable con la estructura del registro del archivo, es el patrón para grabar el archivo.
En esta variable se almacenan los datos a grabar en el archivo.
Cerrar el archivo
Procesamiento de datos
Al momento de procesar los datos almacenados en un archivo, debemos leer y procesar un
registro por vez, de la misma forma que lo haríamos si los datos se ingresan por teclado.
Para poder controlar el fin del archivo debemos leer la marca de EOF y de esa manera controlar el
ciclo de lectura.
Supongamos un programa que lee desde un archivo los datos de inscripción de un alumno, y que
luego de validarlos, si la validación es OK lo graba en el maestro de alumnos, y si la validación es
errónea, lo graba en un archivo de errores. De esta forma, podemos utilizar el mismo
procedimiento Grabar ya que el formato del registro es el mismo tanto para el archivo de datos de
inscripción, como para el archivo de errores.
Mostraremos primero los prototipos de los procedimientos que vamos a utilizar, y a continuación el
diagrama de este proceso.
Suponemos declarados las variables y tipos correspondientes, los nombres que utilizamos son
suficientemente representativos.
/*Declaración de prototipos*/
void AbrirArchivo (srt40 ubicacion, str2 tipoApertura, File * &ArchivoDatos, bool &pudeAbrir)
CerrarArchivo (aNovedad)
CerrarArchivo (aMaestro)
CerrarArchivo (aErrores)
En caso que el archivo esté vacío, la variable bFinNov volverá con TRUE y por lo tanto no
entraremos al ciclo; a continuación veremos la importancia de esta primer lectura adelantada.
Aclaración: De aquí en adelante, y por una cuestión de simplicidad en el procedimiento para abrir
un archivo, indicaremos sólo el modo de apertura y el nombre lógico del archivo, omitiendo el
nombre físico. Por ejemplo:
Corte de Control
El corte de control es una técnica de programación muy utilizada que permite resolver
determinadas situaciones en las cuales es necesario agrupar los registros almacenados en el
archivo de acuerdo a la información almacenada en uno o más campos.
• Para cada sucursal, cuál fue el importe total vendido por cada vendedor.
• Cuál fue la sucursal que más vendió.
Una solución a este ejercicio sería armar una matriz de 20 filas que representarán a las sucursales,
por 10 columnas que representarán a los vendedores y por cada venta ingresada se actualizará
una celda de la matriz acumulando el importe vendido.
De esta manera tendríamos toda la información para que al finalizar el proceso, recorriendo la
matriz podamos mostrar los resultados pedidos.
• Para cada sucursal, cuál fue el importe total vendido por cada vendedor.
• Cuál fue la sucursal que más vendió.
En el caso en que la información esté ordenada por el mismo criterio que nos están pidiendo
informar, se puede aplicar la técnica de corte de control para agrupar los datos y de esta manera
poder informar de acuerdo a lo pedido.
Como podemos observar, si los datos están ordenados, todas las ventas del vendedor 1 de la
sucursal A van a estar juntas, por lo tanto podríamos tener una única variable para acumular las
ventas de los vendedores.
Esta variable la inicializaríamos en 0 antes de procesar las ventas del vendedor 1 de la sucursal A
y cuando cambia el vendedor, mostramos lo que acumulamos en esa variable, que para el ejemplo
sería 83, y la volvemos a poner en 0 para acumular las ventas del siguiente vendedor.
De esta forma, nos alcanza con tener una única variable para todos los vendedores, no importa
cuántos fuesen.
Lo mismo podríamos hacer para las sucursales, si queremos saber cuál es la sucursal que más
vendió, podemos tener una variable que mientras la sucursal que leemos sea la A, vaya
acumulando las ventas y cuando aparece una nueva sucursal, comparamos el acumulado de esa
sucursal con el máximo que tenemos hasta el momento (reemplazándolo si corresponde) y
volvemos a inicializar la variable para hacer lo mismo con las siguiente sucursal.
Programación 2 / Módulo I Pág. 12
INSTITUTO DE TECNOLOGIA O.R.T.
Instituto incorporado a la enseñanza Oficial (A-763)
Cada grupo o jerarquía que necesitemos procesar, va a necesitar de un ciclo donde procesemos
los datos de ese grupo, luego, para controlar este ciclo necesitaremos una variable que
previamente reciba el valor actual del dato por el cual queremos agrupar y en cada vuelta del ciclo
vamos a estar comparando el nuevo dato leído con el contenido de esta variable para ver si
cambió.
Al comenzar cada ciclo, deberemos inicializar también todas las variables que necesitamos para
ese grupo y al finalizar cada ciclo mostraremos los resultados de la actualización de esas variables.
Cada uno de estos ciclos que armamos y anidamos se llama nivel del corte de control y como
dijimos antes que cada agrupamiento necesita de un ciclo, vamos a tener tantos niveles de corte
como agrupamientos sean necesarios.
En el ejemplo anterior en el que tenemos que agrupar por sucursal y vendedor vamos a tener 2
niveles de corte de control.
Aclaración: Vamos a notar que en algunos procedimientos hay “puntos suspensivos”. Esto se debe
a que como es un diagrama genérico, se indican con puntos suspensivos los parámetros que se
pasarían en cada llamada a un procedimiento de acuerdo a un problema dado.
InicioGeneral (bFin, …)
!bFin
clave1Ant sReg.clave1
InicioCorte1 (…...)
clave2Ant sReg.clave2
InicioCorte2 (…...)
(!bFin) && (clave1Ant == sReg.clave1) &&
(clave2Ant == sReg.clave2)
FinCorte2 (…...)
FinCorte1 (…...)
Cerrar (aDatos)
FinGeneral (….…)
Observemos que:
En el diagrama vemos 3 ciclos mientras, el primero es para controlar el fin de los datos y los
dos siguientes para los 2 niveles de corte.
Previo a cada nivel de corte existe un procedimiento para inicializar todas las variables
correspondientes a ese nivel y al final existe otro procedimiento para utilizar los resultados
obtenidos dentro del corte. Los resultados se pueden informar por pantalla, imprimir mediante
una impresora o grabarse en un archivo para otro proceso.
Para poder aplicar la técnica de corte de control, los datos deben estar ordenados por los
campos que queremos agrupar.
• Se debe utilizar el esquema de lectura adelantada para que con la primera lectura se
puedan inicializar las variables que guardan los datos anteriores.
• La primera lectura debe hacerse fuera de todo ciclo y las siguientes siempre en el ciclo más
interno.
• Cada nivel de corte está compuesto de 3 partes, la inicialización de todas las variables a
utilizar en ese nivel, el ciclo donde procesamos los datos y el fin del corte donde se utilizan
los datos almacenados en las variables que se inicializaron y procesaron previamente.
• A medida que se agregan niveles de corte, las condiciones de los ciclos mientras (while) se
van sumando. En el primer ciclo, que es el que controla el fin de los datos, solo tenemos la
condición de fin de ciclo. En el siguiente ciclo, que corresponde al primer nivel de corte,
debemos controlar que no cambie el dato por el cual estamos agrupando, pero también que
nos e terminen los datos. Y así sucesivamente.
Actividades:
• Realizar el seguimiento del diagrama de corte de control con los datos de prueba y analizar
los resultados
Apareo de Archivos
Si bien en este módulo no abordaremos en detalle este problema, que será motivo de análisis más
adelante, mencionamos que un ejemplo clásico de apareo de archivos son los famosos ABM de
novedades, donde se procesan las Altas, Bajas y Modificaciones sobre un archivo maestro. Dichas
Altas, Bajas y Modificaciones vienen informadas en un archivo de novedades, ordenadas por la
misma clave que el archivo maestro. La clave es el campo que permite identificar el registro.
En este proceso, el archivo resultante es un archivo maestro actualizado, y si corresponde, un
archivo con los errores del proceso. El archivo maestro actualizado puede contener registros
nuevos (altas), registros modificados y también no contener registros que estaban en el maestro de
entrada por haber sido dados de baja.
Las inscripciones para concurrir a una conferencia deben realizarse personalmente en alguna de
las dos sedes habilitadas a tal fin, una en la ciudad de Buenos Aires y otra en la ciudad de La
Plata. En cada sede se han registrado los inscriptos consignando para cada uno: número de DNI,
apellido y nombre, teléfono y mail. Ambos archivos de inscriptos son ordenados por DNI (tienen
factibilidad 0/1 por este campo), y remitidos para su procesamiento.
Debemos obtener un archivo de inscripción, ordenado por DNI, que también tendrá factibilidad 0/1
por este campo, con todas las personas inscriptas. Si una persona se anotó en ambas sedes, debe
tener un solo registro en el archivo de inscripción unificado.
Comenzamos por declarar las estructuras necesarias para la resolución del problema y luego
analizaremos la estrategia de resolución y completaremos si es necesario.
//suponemos declarados con typedef los tipos str20 y str15 como cadenas de caracteres de la
longitud indicada.
// estructura del registro para los 3 archivos
typedef struct ty_rInsc{
int DNI;
str20 ApyN;
str15 mail;
str15 tel;
}
Ahora declaramos los registros y los archivos
void main() {
FILE * aInscBA; //archivo de inscriptos en BA
FILE * aInscLA; //archivo de inscriptos en La Plata
FILE * aInscU; //archivo de inscripción unificado
Programación 2 / Módulo I Pág. 17
INSTITUTO DE TECNOLOGIA O.R.T.
Instituto incorporado a la enseñanza Oficial (A-763)
Para resolver el problema, obviamente comenzaremos por abrir los archivos aInscBA y aInscLP
para lectura y aInsc para grabación. Luego iremos leyendo los registros de ambos archivos de
entrada, ordenados por DNI, volcando en el archivo de salida los registros de inscripción de forma
tal que resulten ordenados por DNI y que no haya registros repetidos en el archivo de salida.
Por el momento postergamos la cuestión de cómo controlar el fin del proceso, aunque sabemos
que nuestro trabajo terminará cuando no haya más registros para leer en ninguno de los 2 archivos
de entrada.
Comenzaremos por leer un registro de cada archivo de entrada, la idea es ir procesando
“simultáneamente” los archivos aInscBA y aInscLP, comparando las claves del registro de cada
uno y obrando en consecuencia.
Analicemos qué significan los posibles resultados de comparar rInscBA.DNI con rInscLP.DNI.
Las acciones indicadas en la tabla anterior deberán realizarse mientras haya registros (esto es
inscriptos) en alguno de los 2 archivos de entrada.
¿Qué debemos hacer si no hay más inscriptos en el archivo de aInscLP, pero quedan inscriptos en
aInscBA?
Piense ANTES de continuar leyendo…
Debemos grabar todos los registros restantes del archivo aInscBA en el archivo de salida (aInsc),
procediendo como en (1) del cuadro anterior, hasta alcanzar el fin del archivo aInscBA.
Análogamente si no hubiera más inscriptos en el archivo aInscBA, pero quedaran registros sin
procesar en aInscLP, estos registros deberían grabarse en el archivo aInsc, procediendo como en
el caso (2) del cuadro anterior.
Por último, si se alcanza el fin de archivo en ambos archivos de entrada simultáneamente, es
porque los últimos registros de cada uno tienen igual DNI, caso (3) del cuadro anterior.
Retomamos aquí la cuestión del control del fin del proceso; por lo visto recién, si al alcanzar el fin
de uno de los archivos de entrada, asignáramos al campo DNI (clave) de su registro un valor
suficientemente grande (por ejemplo en este caso 999999999), el DNI de los registros del archivo
que no finalizó resultaría siempre menor que este valor. Por lo tanto se grabaría el archivo de
salida y se volvería a leer del archivo que aun tiene registros, y así hasta alcanzar el fin de este
archivo también.
Si cuando se alcanza el fin del archivo que termina en segundo lugar, procedemos de la misma
forma, asignando un valor suficientemente grande al campo DNI, ya tenemos la condición que
controla el ciclo del proceso de apareo.
Mientras que alguno de los archivos no haya alcanzado el fin, continuamos ciclando, y recién
salimos cuando ambas claves tienen el valor 999999999, cuando ambos archivos alcanzaron el fin:
Este procedimiento lo usaremos para leer ambos archivos de entrada, ya que tienen registros del
mismo tipo, invocándolo en cada caso con los parámetros correspondientes.
CerraraSede (aInscBA)
CerraraSede (aInscLP)
CerraraSede (aInscU)
Observe que nunca se llamará al procedimiento de lectura para un archivo que alcanzó el fin de
archivo. ¿Por qué? Justifique
Piense ANTES de continuar leyendo…
Efectivamente cuando un archivo finaliza, el procedimiento de lectura asigna el valor COTA a la
clave del registro. Por lo tanto las claves (DNI en este caso) de los registros del otro archivo
siempre resultarán menores; por lo tanto se grabarán en el archivo de salida y se leerá sobre este
archivo. Así hasta que este archivo también alcance el fin, en este caso también tendrá COTA en
su campo clave y se saldrá del ciclo.
Actividades:
• Realizar el seguimiento del diagrama anterior con los siguientes datos de prueba, analizar
como se va avanzando en las lecturas de los archivos de entrada y se genera el archivo
resultante.
Por simplicidad sólo incluimos los campos DNI y ApyN en los registros del lote de prueba.
• Proponer otro lote de prueba, o modificar el anterior para que ambos archivos terminen
“simultáneamente” (sugerimos releer el desarrollo de la estrategia de solución).
• ¿Qué ocurre si uno de los 2 archivos de entrada está vacío, esto es, si en alguna de las
sedes no se registró ningún inscripto?
Autoevaluación
Indique si es Verdadera o Falsa cada una de las siguientes afirmaciones
- Entendemos un archivo como una sucesión lógica de registros; los campos de un registro son la
unidad mínima de información del mismo, y se diferencian por el significado dado a cada uno,
pudiendo ser del mismo o distinto tipo (desde el punto de vista de la programación).
- Al momento de procesar los datos almacenados en los archivos, debemos leer y procesar un
registro por vez, de la misma forma que lo haríamos si los datos se ingresaran por teclado.
- Para aplicar la técnica de corte de control, los datos deben estar ordenados por el campo más
significativo de la estructura del registro.
- En un proceso de corte de control se debe utilizar el esquema de lectura adelantada para que con
la primera lectura se puedan inicializar las variables que guardan los datos anteriores.
- En un proceso de apareo, no es necesario que los archivos estén ordenados por el mismo
campo.