Ficheros con el Swift-disk =================================================== El sigte articulo esta dividido en dos partes. El primero es una adaptacion del articulo "No lo olvides, archivalo" pensado esta vez en el Swift Disk I y II. I - No lo olvides, archivalo... con Swift disk. -------------------------------------------- (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 listin 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 lo que 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 pensado para la interfaz Swift Disk, ya sea la I o la II, 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 mas, se deben cambiar las dimensiones de la linea 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 %0;"contador" DATA n() 110 SAVE %0;"nombre" DATA a$() 120 SAVE %0;"apellido" DATA b$() 130 SAVE %0;"telefono" DATA t$() 140 PRINT "Datos almacenados" 150 STOP Si se desea salvar los datos a cinta, omitir entonces todos los "%0;" del listado ya que de lo contrario, se salva todo al disco 0. 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 del disco, tipear: 200 CLEAR 210 LOAD %0;"contador" DATA n() 220 LOAD %0;"nombre" DATA a$() 230 LOAD %0;"apellido" DATA b$() 240 LOAD %0;"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 en cual unidad se desea salvar los datos (en el caso de tener mas de una unidad de disco): 90 INPUT "Disco (0-3)";j El metodo anterior SAVE DATA (unica alternativa con el Basic de casete ya que carece de ordenes OPEN/CLOSE para manejar ficheros) tiene el inconveniente de que hay que guardar toda la cadena aunque solo se use una parte de la misma. La version que sigue a continuacion, pensada para Swift Disk, 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" 110 OPEN #%4;0;"fichero","W","T" 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 Esta version trabaja solo con discos. La linea 110 abre el canal de comunicaciones con el disco. Swift disk permite el uso de cualquier canal del 4 al 15. Es muy importante tipear las lineas tal como se muestran. La linea 110 requiere de punto y coma como separador al inicio, y comas al final ademas de las letras "W" por write (modo escritura) y "T" al final por texto para indicar que es un fichero de tipo secuencial, luego en la orden PRINT# se usa el apostrofe como separador de elementos. La version Swift disk para cargar de nuevo los datos se parece a su procedimiento de escritura excepto que en vez de "W" y PRINT#, se pone "R" por read para solo lectura e INPUT# y las variables son separadas por punto y coma para su correcta lectura: 200 DIM a$(50,15): DIM b$(50,15): DIM t$(50,12) 210 OPEN #%#4;0;"fichero","R","T" 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 ultimo 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", por suerte Swift disk ofrece la funcion %EOF que captura el final del fichero. He aqui el programa completo desde la linea 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) 70 IF a$(n, TO 3)="fin" AND n>50 THEN GO TO 80 50 INPUT "Apellido ";b$(n) 60 INPUT "Numero de Telefono ";t$(n) 70 GO TO 30 80 CLS : PRINT "Almacenando los datos" 110 OPEN #%#4;0;"fichero","W","T" 120 LET l=0: LET NN=N-1 125 LET l=l+1 130 PRINT #4;a$(l)'b$(l)'t$(l) 140 IF l<>NN 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) 210 OPEN #%#4;0;"fichero","R","T" 215 LET l=0 220 LET l=l+1 230 INPUT #4;a$(l): IF %EOF THEN GOTO 250 232 INPUT #4;b$(l);t$(l) 235 PRINT a$(l),b$(l),t$(l) 240 GO TO 220 250 CLOSE #%#4 II - FICHEROS SECUENCIALES Y DIRECTOS: ---------------------------------------------- II.a - Ficheros secuenciales En el Swift disk es indistinto llamarlos ficheros secuenciales o ficheros de tipo texto. En la primera parte vimos claramente como se crean y leen este tipo de ficheros. Tambien se dio un claro ejemplo del uso de %EOF, por lo que ahora pasamos a ver como se le agregan nuevos datos al fichero desde el punto donde lo cerramos anteriormente. Modo APPEND (agregar o aumentar datos): 1100 REM modo append 1110 OPEN #%#4;0;"num2.dat","W","T" 1120 FOR n=100 TO 0 STEP -1 1130 PRINT #4;n 1140 NEXT n 1150 CLOSE #%#4 Para incluir nuevos datos al fichero antes creado, basta con volverlo a abrir otra vez pero esta vez reemplazando W por A, para seguir agregandole nuevos datos: 1210 OPEN #%#5;0;"num2.dat","A","T" 1220 FOR n=1 TO 100 1230 PRINT #5;n 1240 NEXT n 1250 CLOSE #%#5 OPEN A no reinicia el fichero desde cero a menos que el nombre dado no exista. Para resetear el puntero a cero hay que usar OPEN W otra vez para asi eliminar todos los datos del fichero. %EOF y %ERR En otros sistemas como el Microdrive al no haber forma de capturar el final del fichero, es necesario crear una marca muda como "eof","fin" o "zzz". Pero ya que Swift disk tiene una funcion de captura %EOF, esto de la marca muda es aqui ya innecesario. Claro esta, podria requerirse en el programa durante la creacion del fichero pero que ya no debe escribirse. Como ya se ha mencionado en otros apartados Swift disk ofrece la posibilidad de capturar los errores de disco desde el Basic con IF %ERR THEN GOTO xx y usando LET ERROR = %ERR para saber cual es el codigo del error. II.b - Ficheros de acceso directo Hasta ahora hemos visto como leer y a~adir nuevos datos a un fichero secuencial. Pasamos pues a ver como trabajar con ficheros directos o aleatorios. Para que se comprenda mejor como opera Swift disk, veamos el sigte. ejemplo: 1800 DIM X(1) 1802 OPEN #%#4;0;"dat2.num","W","R",3 1810 FOR n=1 TO 20 1820 LET x(1)=n*2: OUT %#4,x(1),n 1830 NEXT n 1840 CLOSE #%#4 1850 STOP 1900 DIM X(1) 1905 OPEN #%#4;0;"dat2.num","R","R",3 1910 FOR n=1 TO 20 1920 IN %#4,x(1),n: PRINT x(1) 1930 NEXT n 1940 CLOSE #%#4 1950 STOP En el ejemplo de ahora, tenemos que los valores son salvados como numeros de un maximo de 3 digitos (esto es indicado en la opcion ' "R",x ' al final de OPEN, donde x es la longitud maxima a salvar dentro del registro dado) y que el puntero de datos es fijado ya no por PRINT# e INPUT#, si no por OUT%# e IN%#. Es aconsejable salvar cadenas de longitud fija para mover el puntero a donde queremos siempre, de lo contrario leeremos los datos erroneamente. El sigte ejemplo lee un fichero en modo directo por su numero de registro: 2340 DIM X(1) 2350 OPEN #%#4;0;"num3.dat","R","R",3 2360 INPUT "Registro #:";reg: IF reg=-1 THEN GO TO 2380 2370 IN %#5;x(1),reg: PRINT x(1) 2375 GO TO 2360 2380 CLOSE #%#4 Un fichero previamente salvado como secuencial "T" no puede ser accedido ni modificado de modo directo "R" y viceversa. Veamos otro ejemplo de trabajo con ficheros de acceso directo: 3000 REM modo rnd write 3005 DIM n$(3) 3010 OPEN #%#4;0;"numx.rnd", "W",R",3 3020 FOR n=1 TO 10 3040 LET n$=STR$ (n*2) 3050 OUT %#4,n$,n 3060 NEXT n 3070 CLOSE #%#4 3080 STOP 3100 REM modo rnd read 3105 DIM n$(3) 3110 OPEN #%#4;0;"numx.rnd", "R","R",3 3120 FOR n=1 TO 10 3140 IN %#4,n$,n 3150 PRINT n$ 3160 NEXT n 3170 CLOSE #%#4 3180 STOP 3200 REM modo rnd rd/wr 3210 CLOSE #%#5:DIM N$(3) 3220 PRINT "Hay solo 10 registros":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 3240 OPEN #%#5;1;"numx.rnd", "R","R",3 3245 IN %#5,n$,reg: CLOSE #%#5 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 OPEN #%#5;1;"numx.rnd", "W","R",3 3285 LET n$= STR$ n: OUT %#5,N$,reg: CLOSE #%#5 3290 GO TO 3220 3300 CLOSE #%#5 III - BETABASIC y SWIFT DISK: Si lo comparamos con el Basic Microsoft, el cual tambien tiene instrucciones para la creacion de ficheros directos tenemos lo sigte.: FIELD es reemplazado por DIM, LSET y RSET por LET, PUT por OUT%# y GET por IN%#. Swift disk salva los numeros como cadenas que ocupan el espacio equivalente a los digitos que lo conforman, asi 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(), las cuales se pueden definir del sigte modo si se carece de BetaBasic: DEF FN C$(n)=CHR$ INT (n/256)+CHR$ (n-INT (n/256)*256) o FN M$(... DEF FN N(c$)=256*CODE c$(1)+CODE c$(2) o 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 ficherso 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. BetaBasic tambien ofrece una funcion EOF(n), la cual no funciona con Swift disk, por suerte Swift disk tiene como ya vimos su propio %EOF. Para terminar este articulo ofrezco este programa originalmente publicado en el manual del Timex FDD 3000, pero convertido para correr en el Swift disk: 100 DIM a$(100) 110 LET end=20000 115 CLOSE #%#4 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";LINE 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 PRINT "Terminado" 620 GO TO END 1000 REM //lee fichero// 1005 OPEN #%#4;0;"addres.r","R","R",100 1010 IN %#4,A$,n: CLOSE #%#4 1930 RETURN 2000 REM //escribe fichero// 2005 OPEN #%#4;0;"addres.r","W","R",100 2010 LET A$=n$+b$+p$+c$: OUT %#4,A$,n 2015 CLOSE #%#4 2020 RETURN Francisco Leon zx_if1@hotmail.com