Introducción al lenguaje C. Ficheros Inexados

Elementos de un programa C. Tipos básicos de datos. E/S básica. Sentencias de control. Funciones. Asignación dinámica de memoria. Ficheros. Ficheros indexados: la interfase Btrieve. Compilación y enlazado. Biblioteca de funciones de Turbo C

  • Enviado por: Juan
  • Idioma: castellano
  • País: España España
  • 25 páginas
publicidad

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:

  • byte 0

Es un byte de control que debe almacenar siempre el valor AC hex.

  • bytes 1-8

Almacenan un nombre que identifica la secuencia de intercalación alternativa ante Btrieve.

  • 256 bytes

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:

  • op

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.

  • bloque

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.

  • datos

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.

  • lonreg

Con este parámetro se pasa la dirección de una variable que contiene la longitud del registro.

  • keyval

Almacena el valor de la clave por la que se está accediendo.

  • nkey

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

  • Si hay palabra de paso se pone en datos, y en longitud se pone su longitud.

  • En nkey se indica el modo de apertura. Los modos habituales son:

-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

    • 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

      • 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:

      0 Palabra de paso requerida para cualquier acceso.

    • 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.

    • 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], &reg[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

      • 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.

      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

      • 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.

      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

      • 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.

      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)

      • La clave K0 es el campo isbn. No admite duplicados. Es de tipo string.

      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)

      • 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.

      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

      • 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.

      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

      • 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".

      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