Ingeniero Técnico en Informática de Gestión
Introducción al lenguaje C. Ficheros Inexados
11
Ficheros indexados:
la interfase Btrieve
Introducción
El Lenguaje C no incorpora instrucciones ni funciones de manejo de ficheros indexados. Para disponer de este tipo de acceso en un programa C debemos recurrir a una gestión propia, lo que resulta excesivamente complejo, o a algún programa comercial que proporcione una interfase adecuada. Uno de los programas más eficientes de gestión de archivos indexados es el programa Btrieve, desarrollado por Novell. En el presente capítulo se describirá una parte importante de Btrieve, pero no se realizará un estudio exahustivo, pues ello merecería un libro monográfico.
Las explicaciones del capítulo se refieren a la versión 5.0, aunque gran parte de lo que se diga es válido para otras versiones.
Descripción de Btrieve
Btrieve es un programa residente en memoria que gestiona, lee, inserta y actualiza registros en los ficheros de datos de las aplicaciones, utilizando para ello los recursos del sistema operativo. En principio, Btrieve fue diseñado para trabajar en entornos monousuario, pero las últimas versiones incorporan operaciones de bloqueo de registros que permiten trabajar en entornos de red. El estudio de este capítulo se circunscribe a entornos monousuario. Para otros trabajos debe consultarse el Manual de Operaciones Btrieve.
Los requerimientos mínimos de Btrieve son los siguientes:
-
Ordenador personal IBM o compatible.
-
128 Kb de memoria.
-
Una unidad de disco.
-
Sistema operativo MS-DOS 2.0 o posterior.
La rutina que queda residente en memoria ocupa un mínimo de 35 kb.
Entre las características de Btrieve que cabe destacar están las siguientes:
-
Soporta hasta 24 claves para cada fichero.
-
Pueden añadirse o eliminarse claves después de creado el fichero.
-
Admite 14 tipos de claves.
-
Permite claves duplicadas (más de un registro con el mismo valor para la clave), modificables, segmentadas (formadas por dos segmentos disjuntos del registro), nulas y descendentes.
-
Maneja ficheros de hasta 4 Mb con un número ilimitado de registros.
-
Puede trabajar con ficheros almacenados en dos dispositivos diferentes.
-
Proporciona 36 operaciones distintas que pueden ejecutarse desde el programa de aplicación.
El flujo de control entre el programa de aplicación y el gestor Brieve es, básicamente, el siguiente:
-
El programa emite una llamada a Btrieve por medio de una función a la que se pasa un bloque de parámetros. La forma de estas llamadas cambia ligeramente de un lenguaje a otro. Más adelante estudiaremos cómo se hace para Turbo C.
-
Una pequeña rutina de interfase incluida en el programa guarda el bloque de parámetros en memoria y llama a la parte residente de Btrieve.
-
Btrieve recibe el bloque de parámetros, los valida, y ejecuta la operación que se haya indicado, por ejemplo la lectura o escritura de un registro en el fichero.
-
Btrieve devuelve los datos apropiados, entre ellos un código que indica si la operación ha tenido éxito o no.
-
Btrieve devuelve el control al programa de aplicación.
Gestión de ficheros Btrieve
Los ficheros Btrieve se crean mediante el programa BUTIL.EXE (se explica más adelante) y se gestionan mediante el Gestor de Datos BTRIEVE.EXE.
Un fichero Btrieve está formado por una serie de páginas. La página es la unidad de transferencia utilizada por Btrieve entre memoria y disco en una operación de E/S. El tamaño de la página se especifica cuando se crea el fichero, y ha de ser un múltiplo de 512 bytes, hasta un máximo de 4096. El tamaño óptimo de la página depende de las características del registro. Más adelante veremos cómo determinar ese valor.
Lás páginas de un fichero Btrieve son de tres tipos:
-
Página de cabecera, también llamada registro de control del fichero (FCR). Contiene información sobre las características del fichero.
-
Páginas de datos, en donde se almacenan los registros de datos.
-
Páginas de índices, que contienen los valores de las claves.
Btrieve almacena en la página de datos tantos registros como le es posible. Es conveniente determinar el tamaño óptimo de la página de datos para aumentar la eficiencia de Btrieve. Para calcular este tamaño óptimo hay que tener en cuenta lo siguiente:
-
Por cada clave duplicada Btrieve almacena 8 bytes extra de información en cada registro.
-
Si el fichero admite registros de longitud variable Btrieve añade 4 bytes por registro.
-
Si se admite truncamiento de blancos se añaden 6 bytes por registro.
-
Cada página requiere 6 bytes para información de cabecera.
Con estos datos es posible determinar el tamaño de página que hace mejor utilización del disco. Veamos un ejemplo. Sea un fichero cuya longitud de registro lógico es 117 bytes, y que utiliza dos claves que admiten duplicados. La longitud del registro físico es:
117 + 2 * 8 = 133 bytes
La siguiente tabla muestra el porcentaje de ocupación para cada página:
TAMAÑO DE PÁGINA |
ÚTIL | NÚMERO DE REGISTROS |
OCUPADO | NO UTILIZADO | % DE PÁGINA OCUPADA |
512 | 506 | 3 | 405 | 107 | 79.1 |
1024 | 1018 | 7 | 937 | 87 | 91.5 |
1536 | 1530 | 11 | 1469 | 67 | 95.6 |
2048 | 2042 | 15 | 2001 | 47 | 97.7 |
2560 | 2554 | 19 | 2533 | 27 | 98.9 |
3072 | 3066 | 23 | 3065 | 7 | 99.8 |
3584 | 3578 | 26 | 3464 | 120 | 96.7 |
4096 | 4090 | 30 | 3996 | 100 | 97.6 |
En este ejemplo vemos que un tamaño de página de 512 bytes es inadecuado, pues por cada 512 bytes se malgastan 107. También vemos que en una página de 4096 bytes se almacenan 30 registros, pero se desperdician 100 bytes, lo que significa que si el número de registros del fichero es elevado, se pierde mucho espacio. El tamaño óptimo parece ser el de 3072 bytes, pues tan solo se pierden 7 bytes cada 23 registros.
Una característica importante de Btrieve es el control que realiza de la consistencia de los datos. Si se produce un fallo en el sistema mientras Btrieve hace actualizaciones en las páginas pueden producirse inconsistencias en el fichero. Para protegerse contra ello Btrieve realiza un proceso llamado preimagen, mediante el cual se restaura automáticamente el fichero a la situación inmediatamente anterior a la operación no completada. Para ello Btrieve utiliza un fichero temporal, llamado fichero preimagen, en el que registra los cambios en el fichero mientras dura la operación. El fichero preimagen tiene el mismo nombre que el fichero de datos Btrieve, pero con extensión .PRE, por lo que debe evitarse esta extensión para los ficheros de datos.
Otro metodo proporcionado por Btrieve para proteger la consistencia de los ficheros es la definición de transacciones. Entre las operaciones aportadas por Btrieve hay dos, denominadas Inicio y Fin de Transacción. Las operaciones Btrieve realizadas entre el inicio y el final de una transacción sólo se actualizarán en el fichero si la transacción tiene éxito. Si el sistema falla antes de completar la transacción, las operaciones Btrieve solicitadas desde el inicio de la transacción no se actualizan en el fichero. Btrieve utiliza un fichero de control de transacción para seguir la pista de los ficheros involucrados.
Otra particularidad de Btrieve es que permite abrir ficheros en modo acelerado para mejorar el rendimiento en operaciones de inserción, actualización y eliminación. Cuando se abre un fichero en modo acelerado Btrieve no escribe páginas en disco hasta que la memoria intermedia está llena y el algoritmo LRU (Last Reciently Used) selecciona un área para ser rellenada.
Por último, Btrieve permite restringir el acceso a ficheros especificando un nombre de propietario o palabra de paso, evitando accesos no autorizados a los datos.
El Gestor de Datos Btrieve
Para que un programa pueda hacer llamadas a Btrieve ha de cargarse previamente en memoria el Gestor de Datos BTRIEVE.EXE, que es quién ejecuta todas las operaciones de gestión de registros y ficheros. Para ello, desde el indicador del DOS debe ejecutarse el programa BTRIEVE.EXE mediante
BTRIEVE [opciones]
Una vez cargado correctamente en memoria aparecerá un mensaje similar a
Btrieve Record Manager Version 5.xx
Copyright (c) 1982, 1988, novell, Inc. All Rights Reserved
Si en la carga se produce algún error, Btrieve envía un mensaje describiendo las características del problema. Si no hay error, Btrieve permanece residente en memoria hasta que se interrumpe la corriente, se recarga el DOS, se descarga mediante el utilitario BUTIL (hablaremos de él más adelante) o desde el programa de aplicación se emite una orden de parada.
La tabla siguiente describe algunas de las opciones de arranque del Gestor de Datos.
OPCIÓN | DESCRIPCIÓN |
/M: Tamaño de memoria | Es un valor comprendido entre 9 y 64 que determina el tamaño de memoria en Kb de las áreas de Btrieve. El valor por defecto es 32 Kb. |
/P: Tamaño de página | Especifica el tamaño de la página. Ha de ser un múltiplo de 512 hasta un máximo de 4096. Si se especifica un tamaño de página de 4096, debe asignarse, al menos, 36 kb para la opción /M. |
/T: Fichero de transacción | Especifica el fichero de control de transacciones. |
/I: Dispositivo del fichero preimagen | Especifica el dispositivo en el que se ubicará el fichero preimagen. |
/F: Ficheros abiertos | Especifica el máximo número de ficheros Btrieve que pueden permanecer abiertos simultáneamente. El valor por defecto es 20. El máximo es 255. |
El utilitario BUTIL
El utilitario BUTIL.EXE es un programa que realiza ciertas operaciones sobre ficheros Btrieve (crear, copiar, ...), permite descargar de memoria el Gestor de Datos, o informar sobre la versión de Btrieve que se está utilizando.
Antes de ejecutar BUTIL debe cargarse en memoria el Gestor de Datos. La sintaxis de BUTIL es la siguiente:
BUTIL -mandato [parámetros] [-O <propietario>]
A continuación se describen algunos de los mandatos de BUTIL.
CLONE
Crea un fichero Btrieve vacío con las mismas características que uno existente. La sintaxis para CLONE es:
butil -CLONE <fichero existente> <fichero nuevo> [-O <propietario>]
COPY
Copia el contenido de un fichero Btrieve en otro. Ambos deben existir. La sintaxis es:
butil -COPY <fich. entrada> <fich. salida> [-O <prop. ent> [-O <prop. Sal>]]
CREATE
Los ficheros Btrieve se crean con esta orden del utilitario BUTIL. Mediante CREATE se crea un fichero Btrieve vacío con ciertas propiedades. Éstas se especifican en un fichero de texto que contiene una lista de parámetros que definen las características del fichero. El fichero que contiene los parámetros se crea con cualquier editor de texto, y contiene sentencias del tipo
palabra_reservada=valor
en donde palabra_reservada se refiere a una característica del fichero o de sus claves, y valor es el valor asignado a dicha característica. La tabla siguiente muestra algunas de las palabras reservadas utilizadas para fijar características generales del fichero.
record=# | Especifica la longitud del registro lógico. El valor # debe estar comprendido entre 4 y 4090 |
variable=<y|n> | Especifica si el fichero contiene o no registros de longitud variable. |
key=# | Especifica el número de claves del fichero. Se admite cualquier valor entre 1 y 24. |
page=# | Especifica el tamaño de página. Debe ser un múltiplo de 512 hasta un máximo de 4096. |
replace=<y|n> | Se utiliza para indicar si se desea que Btrieve cree un nuevo fichero si ya existe uno con el mismo nombre, advirtiendo de su existencia. |
position=# | Especifica la posición, dentro del registro lógico, en que comienza la clave que se describe. |
length=# | Especifica la longitud de la clave. |
duplicates=<y|n> | Determina si se permite o no duplicados en las claves. |
modifiable=<y|n> | Indica si el programa puede modificar el valor de la clave. |
type=tipo | Indica el tipo de clave. Algunos de los tipos de clave permitidos se muestran en una tabla posterior. |
descending=y | Se especifica cuando se quiere mantener el fichero ordenado descendentemente respecto de la clave definida. |
alternate=<y|n> | Se especifica y cuando se desea un criterio de clasificación diferente al ASCII estándar. En ese caso, el nuevo criterio se almacena en un fichero cuya estructura se explica más adelante. |
segment=<y|n> | Indica si la clave tiene o no algún segmento más. |
name=fichero | Especifica el fichero que contiene el nuevo criterio de clasificación si se ha indicado alternate=y. |
La siguiente tabla muestra alguno de los tipos de clave que se pueden especificar con el parámetro type
TIPO | DESCRIPCIÓN |
string | Cadenas de caracteres |
integer | Enteros almacenados en binario (2 bytes) |
float | Números en punto flotante (4-8 bytes) |
numeric | Números almacenados como cadenas de caracteres |
lstring | Como string, especificando la longitus en el byte 0 |
zstring | Cadenas tipo C: finalizadas con el ASCII nulo |
Si en alguna clave se ha especificado la sentencia alternate=y, la última sentencia del fichero debe ser del tipo name=fichero, siendo fichero el archivo que almacena el nuevo criterio de clasificación. Este archivo debe tener la siguiente estructura:
| Es un byte de control que debe almacenar siempre el valor AC hex. |
| Almacenan un nombre que identifica la secuencia de intercalación alternativa ante Btrieve. |
| Almacenan la nueva clasificación. |
Cuando se crea el fichero de parámetros deben tenerse en cuenta las siguientes normas:
-
Todos los elementos deben estar en minúsculas.
-
Deben presentarse en el mismo orden en que se han expuesto en las tablas anteriores.
-
Las sentencias han de ser consistentes. Por ejemplo, si se ha indicado para alguna clave alternate=y, el último elemento del fichero de parámetros debe ser una sentencia name.
Veamos un ejemplo. Sea el siguiente fichero, de nombre DATOS.PAR:
record=113
variable=n
key=2
page=3072
replace=n
position=1 length=5 duplicates=n modifiable=n type=zstring alternate=n segment=n
position=6 length=30 duplicates=y modifiable=y type=zstring alternate=n segment=y
position=46 length=3 duplicates=y modifiable=y type=zstring alternate=n segment=n
Mediante la orden
BUTIL -CREATE DATOS.BTR DATOS.PAR
se crea un fichero llamado DATOS.BTR con las siguientes especificaciones:
-
Registros de longitud fija de 113 bytes
-
Páginas de 3072 bytes
-
Dos claves de acceso definidas de la siguiente manera
Clave no segmentada de 5 bytes, contados desde el primer byte del registro, de tipo zstring, no duplicada y no modificable.
Clave de tipo zstring, duplicada y modificable con dos segmentos: uno de 30 bytes contados a partir del 6º, y otro de 3 bytes a partir del 46º.
LOAD
Permite insertar registros de un fichero secuencial en un fichero Btrieve. La sintaxis es
butil -LOAD <fichero secuencial> <fichero Btrieve> [-O <propietario>]
La estructura de los registros del fichero secuencial debe ser
#,reg<CR+LF>
siendo # la longitud del registro, reg el registro a insertar en el fichero Btrieve, y CR+LF los caracteres retorno de carro y salto de línea. Por ejemplo, si con un editor de texto creamos un archivo DATOS.SEC que contenga
20,ABCDEFGHIJKLMNOPQRST
20,abcdefghijklmnopqrst
y tenemos un fichero Btrieve llamado DATOS.BTR, la orden
BUTIL -LOAD DATOS.SEC DATOS.BTR
inserta los 2 registros de DATOS.SEC en DATOS.BTR.
Es importante asegurarse de que cada línea escrita en el fichero secuencial finaliza con los caracteres Retorno de Carro y Salto de Línea, y de que la longitud de registro especificada es la misma que se indicó al crear el fichero Btrieve.
SAVE
Vuelca el contenido de un fichero Btrieve en un fichero secuencial. Es la operación inversa a LOAD. La sintaxis es
butil -SAVE <fich.Btrieve> <fich.secuencial> <Nº clave> [-O <propietario>]
Los registros creados con SAVE tienen la misma estructura explicada para el mandato LOAD. Si no se especifica lo contrario, el fichero se vuelca ordenado por la clave 0. Si se quiere otro orden se indica en el parámetro Nº clave.
STAT
Muestra en pantalla información con las características de un fichero Btrieve. La sintaxis es
butil -STAT <fichero Btrieve> [-O <propietario>]
STOP
Elimina el Gestor de Datos de memoria. La sintaxis es
butil -STOP
VER
Informa de la versión del Gestor de Datos con que se está trabajando. La sintaxis es:
butil -VER
Interfase de Btrieve con Turbo C
Las operaciones Btrieve en C no utilizan ninguna de las funciones estudiadas en el Capítulo 10. Todas las operaciones sobre ficheros Btrieve se hacen mediante llamadas a una función BTRV, de prototipo
int BTRV (int op, char *bloque, void *datos, int *lonreg, char *keyval, char *nkey);
A continuación se describe cada uno de los parámetros:
| Es un valor entero que indica la operación a realizar sobre el fichero. Las más habituales se describen en el siguiente apartado del capítulo. |
| Es un área de 128 bytes, denominado bloque de posición del fichero, que Btrieve utiliza para un correcto manejo del mismo, inicializándolo en la apertura. Debe asignarse un bloque de posición diferente para cada fichero Btrieve que se abra. |
| Es la dirección de una variable, generalmente de tipo struct, en donde se almacena el registro que va a ser escrito en el fichero y donde se recibe el registro leído del fichero. |
| Con este parámetro se pasa la dirección de una variable que contiene la longitud del registro. |
| Almacena el valor de la clave por la que se está accediendo. |
| Es el número de clave con que se accede al fichero. |
La función BTRV devuelve un valor entero. Si la operación ha tenido éxito, devuelve 0. En caso contrario devuelve un código de error. Los códigos de error se muestran más adelante en el capítulo. Para poder utilizar la función BTRV debe incluirse el archivo turcbtrv.c mediante una sentencia #include como
#include <c:\btr\turcbtrv.c>
suponiendo que el fichero turcbtrv.c se encuentra en el directorio c:\btr. También puede compilarse este fichero y obtener un módulo objeto que se enlace más tarde con el programa (se estudia cómo hacerlo en el Capítulo 12). Veremos más adelante algunos ejemplos de programas que manejan ficheros Btrieve. Antes es necesario conocer las operaciones que se pueden realizar sobre ellos.
Operaciones Btrieve
Vamos a estudiar algunas de las operaciones Btrieve más comúnmente usadas. Se muestran en orden alfabético.
ABORTAR TRANSACCIÓN 21 | ||||||
Deshace todas las operaciones realizadas desde el comienzo de una transacción activa y termina la transacción. | ||||||
op | bloque | datos | lonreg | keyval | nkey | |
A pasar | X | |||||
Devuelve |
ABRIR 0 | ||||||
Abre un fichero Btrieve cuyo nombre se especifica en keyval. | ||||||
op | bloque | datos | lonreg | keyval | nkey | |
A pasar | X | X | X | X | X | |
Devuelve | X | |||||
-1 Acelerado. 0 Apertura normal. | ||||||
ABRIR TRANSACCIÓN 19 | ||||||
Señala el comienzo de una transacción. | ||||||
op | bloque | datos | lonreg | keyval | nkey | |
A pasar | X | |||||
Devuelve |
-
El fichero debe estar abierto y no tener asignada una palabra de paso.
-
La palabra de paso debe colocarse en el parámetro datos y en el parámetro keyval. Debe ser una cadena de hasta 8 caracteres acabada con un nulo.
-
El parámetro nkey se inicializa a un valor que indica el tipo de restricción de acceso asociada al fichero. Los valores posibles son:
-
No se criptografían datos.
-
1 Permiso de lectura sin palabra de paso.
-
No se criptografían datos.
-
2 Palabra de paso requerida para cualquier acceso.
-
Se criptografían datos.
-
3 Permiso de lectura sin palabra de paso.
-
La clave K0 es el campo gru.Admite duplicados.
-
La clave K1 está formada por los campos gru y nom. No admite duplicados.
-
La clave K2 está formada por el campo nom. No admite duplicados.
-
Las tres claves son de tipo string.
-
El campo gru sólo puede almacenar los valores: 1FP2B, 2FP2A, 2FP2B, 2FP2C, 3FP2A y 3FP2B.
-
El campo fal es una matriz entera de 12 filas por 8 columnas que debe interpretarse como sigue: El elemento fal[i][j] se refiere al número de faltas del mes i en la asignatura j.
-
La clave K0 es el campo gru. No admite duplicados. Es de tipo string.
-
El campo gru sólo puede almacenar los valores: 1FP2B, 2FP2A, 2FP2B, 2FP2C, 3FP2A y 3FP2B.
-
El campo asg es una matriz de 8 cadenas de 6 caracteres que almacenan las abreviaturas de los nombres de las asignaturas del grupo. Por ejemplo, PRACT para Prácticas.
-
La clave K0 es el campo fec. Admite duplicados. Tipo string.
-
La clave K1 es el campo dev. Admite duplicados. Tipo string.
-
El campo fec almacena la fecha del préstamo en formato AAAAMMDD.
-
El campo exp almacena sólo dígitos numéricos y está completado con ceros a la izquierda. Por ejemplo, el expediente 65 se almacena como 00065.
-
El campo dev almacena el carácter S si el libro ha sido devuelto, y el carácter N en caso contrario.
-
La clave K0 es el campo isbn. No admite duplicados. Es de tipo string.
-
La clave K0 es el campo exp. No admite duplicados. Es de tipo string.
-
El campo exp almacena sólo dígitos numéricos, y está completado a la izquierda con ceros.
-
El campo alm contiene dos digitos numéricos. Así, el almacén 1 se codifica como "01".
-
El campo ope almacena una E si es una entrada de material, una S si es una salida, y una B si el artículo debe darse de baja en su almacén.
-
El archivo no está ordenado bajo ningún criterio.
-
La clave K0 está formada por los campos alm y art. No se admiten duplicados ni modificaciones. Es de tipo string.
-
La clave K1 coincide con el campo art. Admite duplicados. Es de tipo string.
-
El campo alm contiene dos digitos numéricos. Así, el almacén 1 se codifica como "01".
ACTUALIZAR 3 | ||||||
Actualiza un registro existente en un fichero Btrieve. | ||||||
op | bloque | datos | lonreg | keyval | nkey | |
A pasar | X | X | X | X | X | |
Devuelve | X | X | ||||
Previamente debe haberse realizado con éxito una operación de lectura del registro que se desea actualizar. |
ASIGNAR PALABRA DE PASO 29 | ||||||
Asigna una palabra de paso a un fichero Btrieve para prevenir el acceso al mismo a usuarios no autorizados. | ||||||
op | bloque | datos | lonreg | keyval | nkey | |
A pasar | X | X | X | X | X | X |
Devuelve | X | |||||
0 Palabra de paso requerida para cualquier acceso. Se criptografían datos. |
BORRAR 4 | ||||||
Actualiza un registro existente en un fichero Btrieve. | ||||||
op | bloque | datos | lonreg | keyval | nkey | |
A pasar | X | X | X | |||
Devuelve | X | X | ||||
Previamente debe haberse realizado con éxito una operación de lectura del registro que se desea borrar. | ||||||
CERRAR 1 | ||||||
Cierra un fichero Btrieve. | ||||||
op | bloque | datos | lonreg | keyval | nkey | |
A pasar | X | X | ||||
Devuelve |
ELIMINAR PALABRA DE PASO 30 | ||||||
Elimina la palabra de paso previamente asignada a un fichero Btrieve. | ||||||
op | bloque | datos | lonreg | keyval | nkey | |
A pasar | X | X | ||||
Devuelve | X |
INSERTAR 2 | ||||||
Inserta un nuevo registro en un fichero Btrieve. | ||||||
op | bloque | datos | lonreg | keyval | nkey | |
A pasar | X | X | X | X | X | |
Devuelve | X | X | ||||
El parámetro datos debe almacenar el registro a insertar. |
LEER ANTERIOR 7 | ||||||
Accede al registro inmediatamente anterior al "registro actual". | ||||||
op | bloque | datos | lonreg | keyval | nkey | |
A pasar | X | X | X | X | X | |
Devuelve | X | X | X | X | ||
Anteriormente debe haberse realizado con éxito una operación de lectura. El parámetro keyval debe pasarse tal como fue devuelto en dicha operación. |
LEER IGUAL 5 | ||||||
Accede al 1er registro cuyo valor de clave es el mismo que el que se indica en keyval. | ||||||
op | bloque | datos | lonreg | keyval | nkey | |
A pasar | X | X | X | X | X | |
Devuelve | X | X | X |
LEER INFERIOR 12 | ||||||
Accede al registro correspondiente a la clave más baja de la vía nkey. | ||||||
op | bloque | datos | lonreg | keyval | nkey | |
A pasar | X | X | X | X | ||
Devuelve | X | X | X | X | ||
LEER MAYOR 8 | ||||||
Accede al 1er registro cuyo valor de clave es mayor que el especificado en keyval. | ||||||
op | bloque | datos | lonreg | keyval | nkey | |
A pasar | X | X | X | X | X | |
Devuelve | X | X | X | X |
LEER MAYOR O IGUAL 9 | ||||||
Accede al 1er registro con valor de clave mayor o igual que el indicado en keyval. | ||||||
op | bloque | datos | lonreg | keyval | nkey | |
A pasar | X | X | X | X | X | |
Devuelve | X | X | X | X |
LEER MENOR 10 | ||||||
Accede al 1er registro cuyo valor de clave es menor que el especificado en keyval. | ||||||
op | bloque | datos | lonreg | keyval | nkey | |
A pasar | X | X | X | X | X | |
Devuelve | X | X | X | X |
LEER MENOR O IGUAL 11 | ||||||
Accede al 1er registro con valor de clave menor o igual que el indicado en keyval. | ||||||
op | bloque | datos | lonreg | keyval | nkey | |
A pasar | X | X | X | X | X | |
Devuelve | X | X | X | X |
LEER SIGUIENTE 6 | ||||||
Accede al registro siguiente al "registro actual". | ||||||
op | bloque | datos | lonreg | keyval | nkey | |
A pasar | X | X | X | X | X | |
Devuelve | X | X | X | X | ||
Anteriormente debe haberse realizado con éxito una operación de lectura. El parámetro keyval debe pasarse tal como fue devuelto en dicha operación. |
LEER SUPERIOR 13 | ||||||
Accede al registro correspondiente a la clave más alta para la vía nkey. | ||||||
op | bloque | datos | lonreg | keyval | nkey | |
A pasar | X | X | X | X | ||
Devuelve | X | X | X | X |
PARAR 25 | ||||||
Descarga el Gestor de Datos de memoria y cierra todos los ficheros. | ||||||
op | bloque | datos | lonreg | keyval | nkey | |
A pasar | X | |||||
Devuelve |
TERMINAR TRANSACCIÓN 20 | ||||||
Completa una transacción y confirma las operaciones realizadas desde su inicio. | ||||||
op | bloque | datos | lonreg | keyval | nkey | |
A pasar | X | |||||
Devuelve |
Ejemplos
Veremos ahora algunos ejemplos de programas C que utilizan archivos Btrieve. El primero es un programa que realiza algunas operaciones básicas que se seleccionan desde un menú.
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include "c:\btr\turcbtrv.c"
#define ABRIR 0
#define CERRAR 1
#define INSERTAR 2
#define ACTUALIZAR 3
#define BORRAR 4
#define IGUAL 5
#define SIGUIENTE 6
#define ANTERIOR 7
#define INFERIOR 12
#define SUPERIOR 13
struct REG {
char nombre[26]; // Campo Clave, no dup, no modificable
char direcc[31];
char telef[8];
};
void ErrorBtr (int, int);
void Pantalla (void);
int Opcion (void);
void Presentar (struct REG);
char *Intro (int, int, int, char *);
void main (void)
{
int st;
char bloque[128];
struct REG datos;
int lonreg = sizeof (datos);
char keyval[26];
char opc;
st = BTRV (ABRIR, bloque, &datos, &lonreg, "DATOS.BTR", -1);
if (st) {
ErrorBtr (st, ABRIR);
exit (1);
}
Pantalla ();
while ((opc = Opcion ()) != 'X') {
switch (opc) {
case 'A': Intro (15, 9, 25, datos.nombre);
strupr (datos.nombre);
Intro (16, 9, 30, datos.direcc);
Intro (17, 9, 7, datos.telef);
st = BTRV (INSERTAR, bloque, &datos, &lonreg, keyval, 0);
if (st) ErrorBtr (st, INSERTAR);
else {
printf ("\nRegistro insertado. Pulse una tecla");
getch ();
delline ();
}
break;
case 'B': Intro (15, 9, 25, datos.nombre);
strcpy (keyval, strupr (datos.nombre));
st = BTRV (IGUAL, bloque, &datos, &lonreg, keyval, 0);
if (st) ErrorBtr (st, IGUAL);
else Presentar (datos);
break;
case 'C': st = BTRV (INFERIOR, bloque, &datos, &lonreg, keyval, 0);
if (st) ErrorBtr (st, INFERIOR);
else Presentar (datos);
break;
case 'D': st = BTRV (SUPERIOR, bloque, &datos, &lonreg, keyval, 0);
if (st) ErrorBtr (st, SUPERIOR);
else Presentar (datos);
break;
case 'E': st = BTRV (ANTERIOR, bloque, &datos, &lonreg, keyval, 0);
if (st) ErrorBtr (st, ANTERIOR);
else Presentar (datos);
break;
case 'F': st = BTRV (SIGUIENTE, bloque, &datos, &lonreg, keyval, 0);
if (st) ErrorBtr (st, SIGUIENTE);
else Presentar (datos);
break;
case 'G': st = BTRV (BORRAR, bloque, &datos, &lonreg, keyval, 0);
if (st) ErrorBtr (st, BORRAR);
else {
gotoxy (1, 20);
printf ("Registro borrado. Pulse una tecla ...");
getch ();
delline ();
}
break;
case 'H': Intro (16, 9, 30, datos.direcc);
Intro (17, 9, 7, datos.telef);
st = BTRV (ACTUALIZAR, bloque, &datos, &lonreg, keyval, 0);
if (st) ErrorBtr (st, ACTUALIZAR);
else {
gotoxy (1, 20);
printf ("Registro actualizado. Pulse una tecla ...");
getch ();
delline ();
}
}
}
clrscr ();
st = BTRV (CERRAR, bloque, &datos, &lonreg, keyval, 0);
if (st) ErrorBtr (st, CERRAR);
}
void ErrorBtr (int st, int op)
{
gotoxy (1, 20);
printf ("Error %d en operación %d", st, op);
printf ("\nPulse una tecla ...");
getch ();
gotoxy (1, 20);
delline ();
delline ();
}
void Pantalla (void)
{
clrscr ();
printf ("A: Insertar\n");
printf ("B: Leer registro\n");
printf ("C: Leer inferior\n");
printf ("D: Leer superior\n");
printf ("E: Leer anterior\n");
printf ("F: Leer siguiente\n");
printf ("G: Borrar\n");
printf ("H: Modificar\n");
printf ("X: Salir");
gotoxy (1, 15);
printf ("Nombre: ");
printf ("\nDirecc: ");
printf ("\nTelef.: ");
}
int Opcion (void)
{
int tecla;
do {
gotoxy (1, 11);
printf ("==> Teclee opción: ");
gotoxy (20, 11);
tecla = toupper (getche ());
} while (!strchr ("ABCDEFGHX", tecla));
return tecla;
}
void Presentar (struct REG x)
{
gotoxy (9, 15);
printf ("%-25s", x.nombre);
gotoxy (9, 16);
printf ("%-30s", x.direcc);
gotoxy (9, 17);
printf ("%-7s", x.telef);
}
char *Intro (int f, int c, int tam, char *cad)
{
char aux[50];
register int i;
textattr (WHITE | BLUE * 16);
gotoxy (c, f);
for (i = 0; i < tam; i++) putch (' ');
gotoxy (c, f);
aux[0] = tam + 1;
strcpy (cad, cgets (aux));
textattr (LIGHTGRAY | BLACK * 16);
return cad;
}
Puesto que en la mayoría de las llamadas a BTRV el único parámetro que cambia de una a otra es el código de operación, suele simplificarse la llamada mediante una función que invoque a BTRV de la forma siguiente:
int Btr (int codop)
{
return BTRV (codop, ... );
}
Esto implica declarar como globales las variables Btrieve que se pasan a BTRV. Para el programa anterior la función es
int Btr (int codop)
{
return BTRV (codop, bloque, &datos, &lonreg, keyval, 0);
}
y, por ejemplo, la operación INSERTAR se ejecuta del modo
st = Btr (INSERTAR);
habiendo declarado como globales las variable bloque, datos, lonreg y keyval.
Esta nomenclatura simplifica la escritura de programas que usan ficheros Btrieve. Habitualmente se tendrán que manejar varios ficheros Btrieve en un mismo programa. Puede utilizarse una sola función Btr para hacer las llamadas Btrieve de todos los ficheros, sin más que hacer una cuidadosa declaración de variables. Veamos un ejemplo con un programa que usa dos ficheros Btrieve llamados ARTIC.BTR y PEDIDOS.BTR cuya descripción es la siguiente:
ARTIC.BTR Maestro de Artículos | PEDIDOS.BTR Pedidos a proveedor | |||||
Indexado Btrieve | Indexado Btrieve | |||||
Campo | Descripción | Tipo | Campo | Descripción | Tipo | |
cod | Código del Artículo | char(7) | pro | Código Proveedor | char(7) | |
des | Descripción | char(41) | art | Código del Artículo | char(7) | |
exi | Existencia | int | can | Cantidad a pedir | int | |
min | Mínimo | int | pre | Precio de compra | int | |
opt | Óptimo | int | ||||
pco | Precio de compra | int | ||||
pvp | Precio de Venta | int | ||||
pro | Código Proveedor | char(7) | ||||
El campo cod es la única clave de acceso al fichero. No se admiten duplicados ni modificaciones de claves. Los campos de tipo char incluyen el nulo final. | La única clave está formada por los campos pro y art. No se admiten dupli-cados ni modificaciones de claves. Los campos de tipo char incluyen el nulo final |
El programa inserta un registro en PEDIDOS.BTR por cada registro de ARTIC.BTR cuya existencia está bajo mínimos. En ese caso genera un registro en el que la cantidad a pedir (campo can de PEDIDOS.BTR) se obtiene como la diferencia opt - exi de ARTIC.BTR.
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include "c:\btr\turcbtrv.c"
#define ABRIR 0
#define CERRAR 1
#define INSERTAR 2
#define SIGUIENTE 6
#define INFERIOR 12
#define AR 0
#define PD 1
#define NF 2
struct REGART {
char cod[7];
char des[41];
unsigned exi;
unsigned min;
unsigned opt;
unsigned pco;
unsigned pvp;
char pro[7];
};
struct REGPED {
char pro[7];
char art[7];
unsigned can;
unsigned pre;
};
union REGTOT {
struct REGART ar;
struct REGPED pd;
};
int Btr (int op, int fich);
void BtrError (int st, int op, int fich);
void Cerrar (int fich);
char fichero[NF][13] = { "ARTIC.BTR", "PEDIDOS.BTR" };
union REGTOT reg[NF];
char bloque[NF][128];
int longitud[NF] = { sizeof (struct REGART), sizeof (struct REGPED) };
char keyval[NF][14];
void main (void)
{
int st, i;
for (i = 0; i < NF; i++) {
strcpy (keyval[i], fichero[i]);
st = Btr (ABRIR, i);
if (st) {
BtrError (st, ABRIR, i);
Cerrar (i);
exit (1);
}
}
st = Btr (INFERIOR, AR);
while (!st) {
if (reg[AR].ar.exi < reg[AR].ar.min) {
strcpy (reg[PD].pd.pro, reg[AR].ar.pro);
strcpy (reg[PD].pd.art, reg[AR].ar.cod);
reg[PD].pd.can = reg[AR].ar.opt - reg[AR].ar.exi;
reg[PD].pd.pre = reg[AR].ar.pco;
st = Btr (INSERTAR, PD);
if (st) BtrError (st, INSERTAR, PD);
}
st = Btr (SIGUIENTE, AR);
}
if (st != 9) BtrError (st, SIGUIENTE, AR);
Cerrar (NF);
}
int Btr (int op, int fich)
{
return BTRV (op, bloque[fich], ®[fich], &longitud[fich], keyval[fich], 0);
}
void BtrError (int st, int op, int fich)
{
printf ("\n%s: Error %d en operación %d", fichero[fich], st, op);
printf ("\nPulse una tecla ...");
while (!getch ()) getch ();
}
void Cerrar (int fich)
{
register int i;
int st;
for (i = 0; i < fich; i++) {
st = Btr (CERRAR, i);
if (st) BtrError (st, CERRAR, i);
}
}
Códigos de error Btrieve
La siguiente tabla muestra los valores de retorno posibles devueltos por BTRV si la operación no tiene éxito:
st | DESCRIPCIÓN | st | DESCRIPCIÓN |
1 | Código de operación inválido | 12 | Fichero no encontrado |
2 | Error de E/S | 13 | Error de extensión |
3 | Fichero no abierto | 14 | Error de preapertura |
4 | Clave no encontrada | 15 | Error de preimagen |
5 | No se admiten claves duplicadas | 16 | Error de expansión |
6 | Número de clave incorrecto | 17 | Error de cierre |
7 | Número de clave cambiado | 18 | Disco lleno |
8 | Posicionamiento inválido | 19 | Error irrecuperable |
9 | Fin de fichero | 20 | No está cargado BTRIEVE |
10 | No se permite modificar la clave | 21 | Error en área de clave |
11 | Nombre de fichero inválido | 22 | Error en tamaño de registro |
st | DESCRIPCIÓN | st | DESCRIPCIÓN |
23 | Bloque de posición < 128 bytes | 48 | Error en secuencia alternativa |
24 | Error de tamaño de página | 49 | Error en tipo de clave |
25 | Error de E/S en creación | 50 | Palabra de paso ya asignada |
26 | Número de claves incorrecto | 51 | Palabra de paso inválida |
27 | Posición de la clave incorrecta | 52 | Error al grabar desde memoria |
28 | Longitud del registro incorrecta | 53 | Interfase inválida (Versión) |
29 | Longitud de clave incorrecta | 54 | No se puede leer página variable |
30 | No es un fichero Btrieve | 55 | Error de autoincremento |
31 | Error en extensión | 56 | Índice incompleto |
32 | Error de E/S en extensión | 57 | Error de memoria expandida |
34 | Nombre inválido par extensión | 58 | Área de compresión pequeña |
35 | Error de directorio | 59 | Fichero existente |
36 | Error en transacción | 80 | Conflicto |
37 | Transacción ya activa | 81 | Bloqueo inválido |
38 | Error de E/S en fichero de trans. | 82 | Posicionamiento perdido |
39 | Error de fin/aborto de transac. | 83 | Lectura fuera de transacción |
40 | Demasiados ficheros en transac. | 84 | Registro bloqueado |
41 | Operación no permitida | 85 | Fichero bloqueado |
42 | Acceso acelerado incompleto | 86 | Tabla de ficheros llena |
43 | Dirección inválida (Operación 23) | 87 | Tabla de identificadores llena |
44 | Vía de acceso con clave nula | 88 | Error en modo de apertura |
45 | Error en indicadores de clave | 93 | Tipo de bloqueo incompatible |
46 | Acceso denegado | 94 | Error de alto nivel |
47 | Demasiados ficheros abiertos |
Ejercicios
1. En un Centro de Enseñanza se dispone de una Base de Datos con información sobre las faltas de asistencia a clase de sus alumnos. Dos de los ficheros de dicha Base de Datos se describen a continuación:
ALUMNOS.BTR | Datos de Alumnos Indexado Btrieve | |||
Campo | Descripción | Tipo | Clave | |
gru | Clave del grupo | char(6) | K0, K1 | |
nom | Apellidos y nombre del alumno | char(31) | K1, K2 | |
fal | Faltas mes/asignatura | int 12x8 | ||
GRUPO.BTR | Datos del Grupo Indexado Btrieve | |||
Campo | Descripción | Tipo | Clave | |
gru | Clave del grupo | char(6) | K0 | |
asg | Abreviatura de las asignaturas | char 8x6 | ||
Escribe un programa que solicite por teclado un grupo y un mes, y realice un informe impreso de las faltas de todos los alumnos del grupo durante ese mes, por orden alfabético y totalizando por alumno y asignatura. El formato de dicho informe debe ser el siguiente:
GRUPO: XXXXX FALTAS DEL MES DE: XXXXXXXXXX |
Apellidos y Nombre | abr1 | abr2 | abr3 | abr4 | abr5 | abr6 | abr7 | abr8 | TOT |
xxxxxxxxxxxxxxxxxxxxx | xxx | xxx | xxx | xxx | xxx | xxx | xxx | xxx | xxx |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
xxxxxxxxxxxxxxxxxxxxx | xxx | xxx | xxx | xxx | xxx | xxx | xxx | xxx | xxx |
TOTALES: | xxx | xxx | xxx | xxx | xxx | xxx | xxx | xxx | xxx |
(Los títulos abr1, ..., abr8 son los nombres abreviados de las asignaturas).
2. En la biblioteca de un Instituto se controla el préstamo de libros mediante una Base de Datos formada por los siguientes ficheros Btrieve:
PRESTAMO.BTR | Libros prestados Indexado Btrieve | |||
Campo | Descripción | Tipo | Clave | |
fec | Fecha del préstamo | char(9) | K0 | |
isbn | ISBN | char(11) | ||
exp | Nº de expediente del alumno | char(6) | ||
dev | Devuelto S/N | char | k1 | |
LIBROS.BTR | Maestro de libros Indexado Btrieve | |||
Campo | Descripción | Tipo | Clave | |
isbn | ISBN | char(11) | K0 | |
tit | Título | char(51) | ||
aut | Autor | char(31) | ||
edi | Editorial | char(31) | ||
ALUMNOS.BTR | Datos de alumnos Indexado Btrieve | |||
Campo | Descripción | Tipo | Clave | |
exp | Nº de expediente del alumno | char(6) | K0 | |
nom | Nombre | char(31) | ||
gru | Grupo | char(11) | ||
Teniendo en cuenta que los libros pueden estar prestados un máximo de 7 días, construye un programa que realice un listado de aquellos libros que no han sido devueltos en el plazo indicado. Para ello se asumirá como fecha del día la del sistema. El listado imprimirá 6 fichas por página con el siguiente formato para cada ficha:
Alumno: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | Grupo: xxxxxxxxxx | |
Título: Autor: Editorial: | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | |
Fecha del préstamo: xx de xxxxxxxxxx de xxxx |
3. Disponemos de un fichero secuencial llamado MOVIM.TMP en el que se registran todos los movimientos de artículos en los almacenes de una empresa. La descripción de este fichero es la siguiente:
MOVIM.TMP | E/S de artículos Secuencial | |||
Campo | Descripción | Tipo | Clave | |
alm | Código de almacén | char(3) | ||
art | Código de artículo | char(7) | ||
can | Cantidad | unsigned | ||
ope | Operación E/S/B | char | ||
A partir de este archivo se desea actualizar las existencias en el Maestro de Artículos, ARTIC.BTR, cuya descripción es la siguiente:
ARTIC.BTR | Maestro de Artículos Indexado Btrieve | |||
Campo | Descripción | Tipo | Clave | |
alm | Código de almacén | char(3) | K0 | |
art | Código de artículo | char(7) | K0, K1 | |
des | Descripción del artículo | char(41) | ||
exi | Existencia | int | ||
min | Mínimo | unsigned | ||
opt | Óptimo | unsigned | ||
pvp | Precio de venta | unsigned | ||
pco | Precio de compra | unsigned | ||
Escribe un programa que efectúe dicha actualización de existencias. Para ello has de tener en cuenta:
Si el campo ope de MOVIM.TMP almacena... | La operación a realizar en ARTIC.BTR es: |
E | exi = exi + can |
S | exi = exi - can |
B | Borrar el registro correspondiente |
178 Introducción al Lenguaje C
11. Ficheros indexados: la interfase Btrieve 177
Descargar
Enviado por: | Juan |
Idioma: | castellano |
País: | España |