Ficheros con Disciple y +D ========================== El sigte articulo está dividido en dos partes. El primero es una adaptación del articulo "No lo olvides, archivalo" pensado esta vez en los sistemas operativos Gdos y G+dos. La segunda parte se subdivide a su vez en ficheros secuenciales con +D y Disciple, y ficheros directos en +D con Betados (Bdos) y Unidos. I - No lo olvides, archivalo ---------------------------- (texto condensado y adaptado originalmente publicado en Input Sinclair) Todo programa que maneje gran cantidad de datos ha de contar con alguna forma conveniente de almacenar los datos. Una forma es usar sentencias DATA para almacenar un listín telefonico sencillo, pero si la informacion queda dentro del programa mismo, uno tiene que interrumpir el programa (con BREAK) para modificarlo, lo cual no es muy satisfactorio. Es mucho mejor almacenar la informacion en cinta o disco, los datos en este caso se almacenan en un fichero. Guardando los datos separadamente del "nucleo" del programa se tiene loq ue se llama una memoria virtual: es decir que el programa base puede ser usado con ficheros diferentes, cada uno con su propio numero de registros o campos. El almacenamiento secuencial de datos es uno de los metodos preferidos, ya que su programacion es sencilla y los principios en que se basa son faciles de entender y los datos pueden ser convertidos a un formato que permite su traslado de un programa a otro o de un ordenador a otro inclusive. En un fichero secuencial los datos se almacenan en serie, con un solo byte por separador entre datos. Este articulo explica como crear tus propios ficheros de modo de poderlos incorporar en tus programas. Creacion de fichero: "Listin telefonico" En este programa ejemplo las entradas admitidas son nombre, apellido y numero. La informacion puede ser enviada directamente al fichero, pero es mas conveniente almacenarlo en cadenas para salvar posteriormente toda ella. La primera parte del programa, establece un sencillo bucle que permite introducir los datos. El maximo da datos a ingresar es 50, si se desea más, se deben cambiar las dimensiones de la línea 10: 10 DIM a$(50,15): DIM b$(50,15): DIM t$(50,12): DIM n(1): DIM s$(15) 20 LET n=0 30 LET n=n+1 40 INPUT "Nombre ";a$(n) 50 INPUT "Apellido ";b$(n) 60 INPUT "Numero de Telefono ";t$(n) 70 IF a$(n)<>s$ AND n<50 THEN GO TO 30 Para salvar los datos como matriz en el disco: 80 CLS : PRINT "Almacenando los datos" 100 LET n(1)=n: SAVE d*"contador" DATA n() 110 SAVE d*"nombre" DATA a$() 120 SAVE d*"apellido" DATA b$() 130 SAVE d*"telefono" DATA t$() 140 PRINT "Datos almacenados" 150 STOP Si se desea salvar los datos a cinta eliminar simplemente: "d*", ya que de lo contrario el Disciple salvará todo al disco por defecto. Lectura del fichero: La rutina para leer el contenido de un fichero y trasladarlo a la memoria, es el inverso al de escritura. Para cargar la matriz de datos desde el disco, tipear: 200 CLEAR 210 LOAD d*"contador" DATA n() 220 LOAD d*"nombre" DATA a$() 230 LOAD d*"apellido" DATA b$() 240 LOAD d*"telefono" DATA t$() 250 FOR l=1 TO n(1) 260 PRINT a$(l),b$(l),t$(l) 270 NEXT l Una mejora al programa es añadirle la opcion de elegir si se desea salvar los datos, en cuál unidad de disco: 90 INPUT "Disco (1/2)";j 100 SAVE d j;... En el caso de la rutina de lectura, hay que añadir las sigtes. líneas: 205 INPUT "Disco (1/2)";j 210 LOAD d j;.... Hay otra manera de almacenar los datos en un Disciple. El metodo anterior SAVE DATA tiene el inconveniente de que hay que guardar toda la cadena aunque solo se use una parte de la misma. La versión que sigue a continuación, almacena cada elemento de la cadena separadamente y se detiene cuando los datos se acaban. 10 DIM a$(50,15): DIM b$(50,15): DIM t$(50,12): DIM s$(15) 20 LET n=0 30 LET n=n+1 40 INPUT "Nombre ";a$(n) 50 INPUT "Apellido ";b$(n) 60 INPUT "Numero de Telefono ";t$(n) 70 IF a$(n)<>s$ AND n<50 THEN GO TO 30 80 CLS : PRINT "Almacenando los datos" 100 INPUT "Tipea unidad a usar (1/2)";j 110 OPEN #4,d j,"fichero" OUT 120 PRINT #4;n 125 FOR l=1 TO n 130 PRINT #4;a$(l)'b$(l)'t$(l) 140 NEXT l 150 CLOSE #*4 160 PRINT "Datos almacenados" 170 STOP Al igual que antes se le pide al usuario que teclee el número de la unidad. Esta version trabaja solo con discos. La línea 100 solicita que unidad de disco (1 ó 2) se desea y la línea 110 abre el canal de comunicaciones con el disco. Disciple permite el uso de cualquier canal del 4 al 15, siendo el 4 el más usado con frecuencia. Es muy importante teclear las líneas tal como se muestran. La línea 110 requiere una coma como separador, mientras la línea 130 exige un pto. y coma luego de la orden PRINT# y el apostrofe como separador de elementos. La version para cargar de nuevo los datos se parece a su procedimiento de escritura excepto que en vez de PRINT#, se pone INPUT# y las variables son separadas por pto. y coma para su correcta lectura: 200 DIM a$(50,15): DIM b$(50,15): DIM t$(50,12) 205 INPUT "Tipea unidad a usar (1/2)";j 210 OPEN #4,d j,"fichero" IN 215 INPUT #4;n 220 FOR l=1 TO n 230 INPUT #4;a$(l);b$(l);t$(l) 235 PRINT a$(l),b$(l),t$(l) 240 NEXT l 250 CLOSE #*4 Marca de fin de fichero (EOF) El último programa usaba la variable N en el bucle que controla el procedimiento de lectura, pero no siempre es posible saber de antemano cuantos datos hay que leer. Un modo de salvar el inconveniente es usando una marca de "fin de fichero", pero desgraciadamente Disciple carece de una funcion EOF() que capture el final del fichero (pero como veremos luego, uno puede poner su propia marca muda). Al no haber EOF(), la unica forma de detectar el final de un fichero es usando una variable muda pues como ya dijimos, no hay otro modo de hacerlo. Podría ser la la palabra "FIN", o ZZZ, ó 999, o lo que uno quiera usar y que no se espere dentro del cuerpo del fichero. El Disciple solamente permite crear ficheros secuenciales con OPEN, para lo cual hay que modificar la línea 70 y eliminar DIM s$(15), ahora innecesaria. He aquí el programa completo desde la línea 5 para poder compararlo con las versiones anteriores: 10 DIM a$(50,15): DIM b$(50,15): DIM t$(50,12) 20 LET n=0 30 LET n=n+1 40 INPUT "Nombre ";a$(n) 50 INPUT "Apellido ";b$(n) 60 INPUT "Numero de Telefono ";t$(n) 70 IF a$(n, TO 3)<>"fin" AND n<50 THEN GO TO 30 80 CLS : PRINT "Almacenando los datos" 100 INPUT "Tipea letra de unidad (1/2)";j 110 OPEN #4,d j,"fichero" 120 LET l=0 125 LET l=l+1 130 PRINT #4;a$(l)'b$(l)'t$(l) 140 IF a$(l, TO 3)<>"fin" AND l<50 THEN GO TO 125 150 CLOSE #*4 160 PRINT "Datos almacenados" 170 STOP 200 DIM a$(50,15): DIM b$(50,15): DIM t$(50,12) 205 INPUT "Tipea letra de unidad (1/2)";j 210 OPEN #4,d j,"fichero" 215 LET l=0 220 LET l=l+1 230 INPUT #4;a$(l);b$(l);t$(l) 235 PRINT a$(l),b$(l),t$(l) 240 IF a$(l, TO 3)<>"fin" AND l<50 THEN GO TO 220 250 CLOSE #*4 II - +D y Disciple - Ficheros secuenciales ------------------------------------------- Creacion de un fichero En el +D, el nombre del fichero debe de cumplir los convenios de nombres propio del SPECTRUM, siendo el nombre de hasta 10 caracteres. Nota: Para la explicacion de los comandos del G+dos, ver el manual del Gdos y G+dos. Como ejemplo vamos a crear un fichero que contenga los numeros del 1 al 100: 100 OPEN #4,d*,"num.dat" OUT 120 FOR n=1 TO 100 130 PRINT #4; n 140 NEXT n 150 PRINT #4;-1 160 CLOSE #*4 170 STOP La línea 150 genera la marca muda de fin de fichero. Una variante del ejemplo anterior, salvando los datos como cadenas. Podemos añadir la sigte línea al ejemplo anterior: 105 DIM n$(3) y modificamos l;a línea que salva los datos del sigte. modo: 130 LET n$=STR$ n: PRINT #4; n$ 150 PRINT #4;CHR$ 0 Lectura de un fichero Una vez que el fichero ha sido creado y guardado en el disco, se puede recuperar o accesar cuando se desee. La sigte. rutina permite leer todo el fichero salvado hasta alcanzar la marca muda que sirve de EOF: 300 OPEN #4,d*,"num.dat" 320 INPUT #4; n 330 IF n=-1 THEN GO TO 360 340 PRINT n 350 GO TO 320 360 PRINT "fin de fichero" 370 CLOSE #*4 Ahora para leer datos separadamente, habría que llamar a la subrutina por cada variable de datos en el fichero, como muestra el sigte ejemplo: 1000 OPEN #6,d*,"prb.dat" OUT 1010 PRINT #6;"prueba"'"#2","numero";128 1020 CLOSE #*6 1050 OPEN #6,d*,"prb.dat" IN 1060 INPUT #6; n$; m$: PRINT n$'m$ 1070 CLOSE #*6 1075 STOP Nota: en caso de que la cadena no se lea correctamente es mejor usar por ejemplo... 1060 INPUT #6; LINE n$; LINE m$ Añadiendo datos a un fichero secuencial No existe un modo APPEND en el +D, cualquier intento de añadirle nuevos datos al fichero reabriendolo, hará que se reinicie, perdiendose así todo lo antes salvado. El único metodo a aplicar es crear un fichero nuevo que sirva de base temporal, pasar todos los datos a este, y una vez terminado todo el proceso, eliminar el fichero anterior y renombrar el temporal con el nombre antiguo. 1100 REM modo append 1110 OPEN #4,d*,"num2.dat" OUT 1120 FOR n=100 TO -1 STEP -1 1130 PRINT #4;n 1140 NEXT n 1150 CLOSE #* 1160 STOP 1210 OPEN #4,d*,"num2.dat"IN 1220 OPEN #5,d*,"temp.dat" 1230 INPUT #4;n 1240 IF n=-1 THEN GO TO 1270 1250 PRINT #5;n 1260 GO TO 1230 1270 FOR n=1 TO 100 1280 PRINT #5;n 1290 NEXT n 1300 PRINT #5;-1 1310 CLOSE #* 1320 ERASE d*"num2.dat" 1330 ERASE d*"temp.dat" TO "num2.dat" 1500 OPEN #5,d*,"num2.dat" 1510 INPUT #5;n 1520 IF n=-1 THEN GO TO 1550 1530 PRINT n 1540 GO TO 1510 1550 CLOSE #* 1555 STOP Esta vez los datos han sido salvados con una marca muda de EOF, así que la línea 1240 la detecta para no añadirla al fichero con los futuros datos que se pondrán ya que entonces el fichero acabaría con un montón de marcas mudas en diferentes partes de la misma, a medida que seagreguen datos futuros, cosa que no deseamos que pase. EOF - versión 1 El sigte ejemplo lee los datos hasta encontrar la marca muda, en mi caso, uso CHR$ 0: 1300 REM eof 1 1310 OPEN #6,d*,"num2.dat" IN 1315 LET a$="" 1320 LET m$=INKEY$#6 1330 LET EOF=(m$=CHR$ 0): IF EOF THEN GO TO 1390 1340 IF m$=CHR$ 13 THEN GO TO 1370 1350 LET a$=a$+m$ 1360 GO TO 1320 1370 LET n=VAL a$ 1380 PRINT n 1385 GO TO 1315 1390 CLOSE #*6 1400 STOP EOF - versión 2 En este caso en vez de usar una variable EOF, he elegido crear una FN E() por EOF(). Añadir: 1305 DEF FN e(n$)=(n$=CHR$ 0) Y modificar: 1330 IF FN E(m$) THEN GO TO 1490 Esta subrutina contabiliza los caracteres uno a uno hasta alcanzar el fin del fichero: 9100 REM 9110 LET zz=1 9120 LET EOF=(INKEY$#chn=CHR$ 0): IF EOF THEN RETURN 9140 LET zz=zz+1 9150 GO TO 9120 EOF - solo Disciple La sigte. rutina funciona solamente en el Disciple, pero no en el +D, el cual no admite la variable ern y por lo tanto no captura el error ni el eof(*). 1600 REM on error y eof 1605 LET trap=23728: LET ern=23610: LET eof=27 1610 POKE trap,255 1615 OPEN #5,d*,"num2.dat" 1620 INPUT #5;n 1630 LET err=PEEK ern: IF ERR=EOF THEN GO TO 1640 1635 PRINT n: GO TO 1620 1640 POKE trap,0: POKE ern,255 1645 CLOSE #* (*) Trap impide que los errores generados por el disco interrumpan el programa, pero en el +D no hay modo de saber la causa ni como responder al respecto, así que es solo util si se sabe el error de antemano y se busca evitar que se detenga el programa debido al error y dé un mensaje. En el +D, hay que omitir la definición de 'ern' y 'eof' en la línea 1605, además de: 1600 REM eof (version de OUTLET 57) 1605 LET trap=23728 1610 OPEN #5,d*,"num2.dat" IN 1615 LET n$="" 1620 POKE trap,255: REM (stop error) 1630 INPUT #5;n$ 1635 POKE trap,0: REM (restore error) 1640 IF n$="" THEN GO TO 1650 1645 PRINT n$: GO TO 1615 1650 CLOSE #* Otros usos de este truco en +D, mencionados en OUTLET 65. En el caso de cargar un archivo en código máquina: 1000 REM detectando error de carga de CODE 1010 POKE 55555,99 ' o cualquier valor 1015 POKE 23828,1 1020 LOAD n$ CODE 55555 1025 POKE 23828,0 1030 IF PEEK 555555 =99 THEN GOTO ... En el caso de una matriz previamente salvada: 1010 DIM x$(1) 1015 POKE 23828,1 1020 LOAD n$ DATA x$() 1025 POKE 23828,0 1030 IF LEN x$(1)=1 THEN ... +D y Betados - APPEND y EOF(): Todo lo anterior es valido tanto para el +D como para el Disciple, a continuación vamos a tratar exclusivamente de un +D con sistema operativo Betados. Para empezar añadiremos la linea siguiente a todos nuestros ficheros: 50 DEF FN p(x)=USR 8: DEF FN l(x)=USR 8: DEF FN e(x)=USR 8 FN p() lee el puntero en curso, FN l() lee la longitud del fichero y FN e() nos dice si hemos llegado o no al final del fichero. Para leer un fichero que cerramos con o sin marca muda (esta última es ya innecesaria): 300 REM eof 310 OPEN #4,d*,"num.dbs"RND 320 INPUT #4;n 330 IF FN e(4) THEN GO TO 360 340 PRINT n 350 GO TO 320 360 PRINT "fin de fichero"'FN l(4) 370 CLOSE #* 380 STOP Una modificación podría ser: 330 LET eof=FN e(4): IF EOF THEN GO TO 360 Esto funciona solamente si los ficheros son creados y leidos con la opcion RND en vez de IN y OUT, así, para añadir datos a un fichero secuencial: 1100 REM modo append 1110 OPEN #4,d*,"num2.dbs"RND 1120 FOR n=100 TO -1 STEP -1 1130 PRINT #4;n 1140 NEXT n 1150 CLOSE #* 1160 STOP 1210 OPEN #5,d*,"num2.dbs"RND 1220 LET d=(FN l(5))-3 1230 POINT #5,d 1240 FOR n=1 TO 100 1250 PRINT #5;n 1260 NEXT n 1270 PRINT #5;-1 1280 CLOSE #* 1300 OPEN #5,d*,"num2.dbs"RND 1310 INPUT #5;n 1320 IF n=-1 THEN GO TO 1350 1330 PRINT n 1340 GO TO 1310 1350 CLOSE #* 1360 STOP La línea 1110 crea un fichero RND secuencial, al cual se le podrán añadir más datos a futuro. La línea 1220 lee la longitud máxima del fichero y le resta el valor necesario para evitar la marca muda (en el caso de que el fichero haya sido salvado de ese modo). La línea 1230 mueve el puntero al punto a partir del cual se harán los añadidos. Otro ejemplo: 1400 OPEN #5,d*,"chr2.dbs"RND 1410 FOR n=35 TO 127 1420 PRINT #5;CHR$ n+STR$ n 1430 NEXT n 1440 CLOSE #*5 1450 STOP 1500 OPEN #5,d*,"chr2.dbs"RND 1505 LET d=FN l(5) 1510 POINT #5,d 1520 FOR n=127 TO 35 STEP -1 1530 PRINT #5;CHR$ n;n 1535 NEXT n 1540 CLOSE #*5 1550 STOP La línea 1505 lee hasta el final del fichero ya que no hubo marca muda. Betados también permite mover datos de ficheros existentes dentro de uno nuevo: 10 OPEN #5;dl"combinado"OUT 20 MOVE d1"primero" TO #5 30 MOVE d1"segundo" TO #5 40 CLOSE #*5 Nota: esta opcion no funciona en el Disciple, el cual aceptaría solo la línea 20 pero ignorará la línea 30 y cualquier PRINT # que le siga, impidiendo así que se pueda usar MOVE para añadirle más datos a un fichero y expandirlo. +D y Betados - Ficheros de acceso directo Por alguna razón los autores no dotaron de facilidades para manejar ficheros directos o la posibilidad de añadir más datos a un fichero con el Disciple o el +D. En cambio con Betados para +D, ya es posible tener todas las facilidades para manejar ficheros tanto secuenciales como directos, manteniendo una sintaxis simple y estandar. Pasamos a ver como manejar ficheros de acceso directo con Betados. El truco es con POINT#, pero para comprender mejor como opera veamos el sigte ejemplo: 1600 OPEN #5,d*,"num2.dbs"RND 1605 PRINT FN p(5) 1610 INPUT "Registro #?";n 1615 IF n=-1 THEN GO TO 1640 1620 POINT #5,n 1630 INPUT #5;m$ 1635 PRINT n,m$: GO TO 1610 1640 PRINT FN l(5): CLOSE #* POINT# mueve el puntero a n, pero eso nos devuelve un valor irregular y no necesariamente el numero que fue salvado como una cadena, por lo tanto debemos de salvar cadenas de longitud fija para mover el puntero a donde queremos ir exactamnete, de lo contrario leeremos los datos erroneamente. El sigte ejemplo lee un fichero en modo directo: 2350 OPEN #4,d*,"num3.dat" RND 2360 INPUT "Registro #:";reg: IF reg=-1 THEN GO TO 2380 2361 IF reg>10 THEN LET reg=reg+1 2365 POINT #4,(reg-1)*2+1 2370 INPUT #4; a$ 2371 PRINT a$ 2375 GO TO 2360 2380 CLOSE #*4 2385 STOP Un fichero RND previamente salvado como secuencial puede ser igualmente accedido y modificado de modo directo tal como nos muestra el ejemplo anterior. Vamos a escribir a continuacion un programa que salva los datos directamente: 3000 REM modo rnd write 3005 DIM n$(3) 3010 OPEN #4,d*,"numx.rnd" RND 3020 FOR n=1 TO 10 3030 POINT #4,n*3 3040 LET n$=STR$ (n*2) 3050 PRINT #4;n$ 3060 NEXT n 3070 CLOSE #*4 3080 STOP 3100 REM modo rnd read 3105 DIM n$(3) 3110 OPEN #4,d*,"numx.rnd" RND 3120 FOR n=1 TO 10 3130 POINT #4,n*3 3140 INPUT #4; n$ 3150 PRINT n$ 3160 NEXT n 3170 CLOSE #*4 3180 STOP 3200 REM modo rnd rd/wr 3210 OPEN #4,d*,"numx.rnd" RND 3220 INPUT "registro #:";reg 3225 IF reg<1 THEN GO TO 3300 3226 IF reg>10 THEN INPUT "Registro inexistente intente de nuevo";v$: GO TO 3220 3230 POINT #4,reg*3 3240 INPUT #4; n$ 3250 INPUT "El registro ";(reg)'"contiene el valor: ";(n$)'"Desea modificarlo? ( s/n) ";v$ 3260 IF v$<>"s" AND v$<>"S" THEN GO TO 3220 3270 INPUT "Ingrese nuevo valor: ";n: IF n=0 THEN GO TO 3220 3280 PRINT #4;n 3290 GO TO 3220 3300 CLOSE #*4 8990 STOP Primero hemos dimensionado la cadena a salvar con DIM, luego posicionamos el puntero del registro con POINT#. El subindice empieza a partir de 1, lo cual hace que la formula sea: (indice * dim), lo cual nos da el n*3 del ejemplo. Sin embargo eso hace que no empiece con el indice 1 sino 3; para forzar el indice a 1, la formula debe ser como sigue: ((indice - 1) * dim) + 1. Ahora, el programa debería funcionar tal como uno espera que lo haga, pero no es así. La rutina de creación del fichero directo fallará precisamente en la línea 3030, esto es debido a que el Betados no deja crear un fichero usando POINT# en su primera vez, en cambio permite leer o modificar un fichero existente. Para evitar que se dé un error en la ejecución, uno debe crear el fichero y llenarlo con cualquier valor solo para inicializarlo, cerrarlo, y volverlo a abrir para recién añadirle datos directamente posicionando el puntero mediante POINT#. Para inicializar el programa anterior hay que añadirle las sigtes. líneas: 2000 REM init rnd file 2010 OPEN #4,d*,"numx.rnd" RND 2020 PRINT #4;999 2030 CLOSE #* Nota: la línea 2020 es necesaria pues si se crea un fichero vacío, POINT# dará un mensaje de error y se interrumpirá el programa. Unidos - Disciple y +D El Betados es un sistema mejorado que corre solo en +D, y se carga desde un disco de arranque, pero no hay version para Disciple. Unidos viene en cambio en formato de ROM que debe ser colocada en la placa de la interface reemplazando a las ROMs originales. Una vez hecho esto el Disciple o el +D trabajan con el nuevo sistema operativo mejorado, el cual añade también manejo de ficheros de acceso directo, entre otras cosas. El truco es también con POINT#, pero a diferencia del Betados, la opción RND requiere de dos parámetros, solo para la creación del fichero, pero ninguno para su lectura. El primer parametro es la cantidad máxima de registros por la cantidad de caracteres que contendrá cada registro. El segundo parámetro es opcional y refiere al byte con el que se inicializará todo el fichero a usar. Ejemplo: 1000 OPEN #4;d*;"c2$.rnd" RND 30 1010 DIM b$(5) 1020 FOR n=1 TO 5 1030 INPUT b$ 1040POINT #4;(n-1)*5+1 1050 PRINT #4;b$ 1060 NEXT n 1070 CLOSE #*4 1100 OPEN #4;d*;"c2$.rnd" RND 1110 DIM b$(5) 1120 FOR n=1 TO 5 1140POINT #4;(n-1)*5+1 1143 INPUT #4;b$: PRINT b$ 1150 NEXT n 1160 CLOSE #* La sintaxis de RND es: 'RND num.reg * (dim + 1)', por lo que el 30 del ejemplo es debido a que 5 es el numero de registros de la base y 6 resulta del 5 de DIM más 1 para almacenar el caracter separador 13; mientras POINT# aplica la misma fórmula que el Betados con el indice empezando en 1. Nota: Unidos posee las funciones (LEN # canal) y (POINT # canal) equivalentes a FN L(c) y FN P(c) del BETAdos, pero ninguna funcion EOF. Debido a la necesidad de conocer y limitarse al máximo de registros en un fichero aleatorio, es imposible añadirle nuevos datos más allá de la longitud especificada en el parámetro RND, a diferencia del BETAdos. Para poder trabajar con un fichero, dedicandole el mayor espacio existente en el disco, suponiendo que quedan 600 k libres y la base de datos llegará a crecer hasta ese punto, habría que hacer RND = 600000 y llenar todo con 32 (espacio). Ejemplo: 1100 OPEN #4;d*;"c5$.rnd" RND 600000,32 1105 CLOSE #* Esto inicializa el fichero para su futuro uso con 1200 OPEN #4;d*;"c5$.rnd" RND a partir de lo cual se podrá recién añadir, leer o modificar con toda tranquilidad, pero nunca pasarse de esa longitud especificada. EOF - en Unidos La sigte. rutina secuencial funciona solamente en el Unidos, el cual es similar al del Disciple y captura el eof como error. 1600 REM on error y eof 1605 LINE 1630: POKE @99,0: LET eof=11 1615 OPEN #5,d*,"num2.dat" IN 1620 INPUT #5;n 1630 LET eof=(Peek @99): IF ERR=EOF THEN GO TO 1640 1635 PRINT n: GO TO 1620 1640 LINE 0: POKE @99,0 1645 CLOSE #* La razón de eof=11 en el ejemplo, es debido a que Unidos no lo captura como error 8, que es el mensaje de "fin de fichero" sino como error "sin sentido en basic" que es el 12. Se vuelve 11 porque (PEEK @99) captura el número de error de Basic y le resta 1. Los errores propios de disco dan valores mayores a 127. APPEND - en Unidos Un truco para actualizar ficheros secuenciales en Unidos, siempre que no se salven los datos con marca muda, es usando MOVE, para pasar la información a un fichero temporal y luego renombrandolo del modo sigte: 10 OPEN #5,d*"temp.dat" OUT 20 MOVE d*"num.dat" TO #5 30 PRINT #5;"añadiendo datos al final del fichero" 40 CLOSE #* 60 MOVE OVER d*"temp.dat" TO "num.dat" También es posible mover datos de un fichero directo a otro: 10 OPEN #5,d*"num2.rnd" RND 42 20 MOVE d*"num1.rnd" TO #5 30 PRINT (POIMT #5) 40 CLOSE #* 60 MOVE d*"num2.rnd" TO #2 La línea 30 nos dice adonde ha sido movido el puntero tras MOVE, de ese modo, podemos seguir insertando más datos luego, siempre que al fichero se le haya designado el espacio suficiente en el parámetro RND. RND también permite leer y modificar un fichero creado con OUT, pero no añadirle más datos de los que su longitud prefijada le permite. Nota: Si el fichero existente es vuelto a abrir en modo escritura, Unidos pregunta si se desea sobreescribir el fichero, si uno responde sí igual dará un error y borrará el fichero del disco. Basta con ignorar el mensaje, hacer CLOSE# y ejecutar de nuevo el programa para continuar sin más problemas. Betabasic 3 y 4: +D salva los numeros como cadenas que ocupan el espacio equivalente a los digitos que lo conforman, así 5, ocupa 1 caracter, mientras 22, 105, 1500 y 45000 ocupan 2, 3, 4, y 5 caracteres respectivamente. Para compactar los valores enteros hay dos funciones en el Basic Microsoft que son muy utiles para salvar numeros, y son MKI$ (make integer) y CVI (convert integer) los cuales sirven para convertir un valor entero a cadena de dos digitos y viceversa. BetaBasic ofrece sus equivalentes en CHAR$() y NUMBER(), pero si no se tuviera, lo unico que nos queda es definir nuestras propias versiones: DEF FN C$(n)=CHR$ INT (n/256)+CHR$ (n-INT (n/256)*256) ó FN M$(... DEF FN N(c$)=256*CODE c$(1)+CODE c$(2) ó FN C(... (*) Ejemplos: 100 REM en el programa de escritura 110 DIM x$(2) 120 LET x$=CHAR$(x) 100 REM en el programa de lectura 120 LET a=NUMBER(a$) Existen otras funciones en el Basic Microsoft asociadas a los ficheros directos y que son: MKS$ (make single), CVS (convert single), MKD$ (make double) y CVD (convert double), los cuales solo tienen su equivalente en la funcion FP$(floating point) del Betabasic 4. Nota: La sentencia ON ERROR del BB no puede capturar los errores de disco del +D. La funcion EOF(n) del BB tampoco funciona, pero Betados tiene su propia FN E() para eso. Para terminar este articulo ofrezco este programa originalmente publicado en el manual del Timex FDD 3000, pero modificado para correr en el +D con Betados: 10 REM RUN para ejecutar e inicializar por primera vez 20 REM RUN 110 todas las demas veces 30 REM GOTO 120 para continuar tras una interrupcion o error 100 OPEN #4,d*,"address.r"RND: PRINT #4;999: CLOSE #* 110 LET end=20000 115 OPEN #4,d*,"address.r"RND: DIM a$(100) 120 INPUT "1=Leer,2=Escribir y 3=Fin";h$ 130 IF h$="2" THEN GO TO 500 135 IF h$="3" THEN GO TO 610 140 IF h$<>"1" THEN GO TO 120 150 REM lee un registro 160 INPUT "Registro numero: ";n 170 IF n>65535 OR n<1 THEN GO TO 160 180 GO SUB 1000 190 CLS 200 PRINT AT 4,3;"Nombre ";a$( TO 30) 210 PRINT AT 8,0; "Direccion ";a$(31 TO 60) 220 PRINT AT 12,2; "Telefono ";a$(61 TO 75) 230 PRINT AT 16,2; "Notas ";a$(76 TO ) 240 INPUT " para continuar";h$ 250 GO TO 120 500 REM escribe un registro 510 INPUT "Registro numero: ";n 520 IF n>65535 OR n<1 THEN GO TO 510 530 CLS 540 DIM n$(30): DIM b$(30): DIM p$(15): DIM c$(25) 550 INPUT "Nombre ";n$ 560 INPUT "Direccion ";b$ 570 INPUT "Telefono ";p$ 580 INPUT "Notas ";c$ 590 GO SUB 2000 600 GO TO 120 610 CLOSE #*4: PRINT "Terminado" 620 GO TO END 1000 REM //lee fichero// 1010 POINT #4,(n-1)*100+1 1020 INPUT #4; a$ 1930 RETURN 2000 REM //escribe fichero// 2005 POINT #4,(n-1)*100+1 2010 PRINT #4;n$+b$+p$+c$ 2020 RETURN Para convertir este programa al Unidos, hay que modificar la línea 110, eliminando el PRINT# y añadiendole al RND el valor equivalente al DIM + 1 por el máximo de registros que uno tenga pensado escribir, o el máximo valor equivalente al espacio libre en el disco. Francisco Leon zx_if1@hotmail.com