Ficheros en el +3 y +3e Debido a la falta de articulos sobre el manejo de ficheros con el +3 y el mas reciente +3e, he decido escribir estas notas, siendo la primera parte una version condensada de un articulo originalmente publicado en la revista Input Sinclair entonces pensada para el uso de Microdrives y casete, pero que ahora he modificado para su uso con +3 y +3e. La segunda parte trata exclusivamente sobre la forma como el +3e maneja los ficheros tanto secuenciales como aleatorios. 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: 80 CLS : PRINT "Almacenando los datos" 100 LET n(1)=n: SAVE "contador" DATA n() 110 SAVE "nombre" DATA a$() 120 SAVE "apellido" DATA b$() 130 SAVE "telefono" DATA t$() 140 PRINT "Datos almacenados" 150 STOP Si se desea salvar los datos a cinta hacer previamente: SAVE "t:", ya que de lo contrario +3 salvará todo al disco A por defecto. LOAD "t:" para cargar de cinta en vez de disco. 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 de cinta o disco, tipear: 200 CLEAR 210 LOAD "contador" DATA n() 220 LOAD "nombre" DATA a$() 230 LOAD "apellido" DATA b$() 240 LOAD "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 el disco o cinta: 90 INPUT "Disco (a/b) o Cinta (t)";j$ 95 SAVE j$+":" En el caso de la rutina de lectura, hay que añadir las sigtes. líneas: 205 INPUT "Disco (a/b) o Cinta (t)";j$ 207 LOAD j$+":" Hisoft Basic 1.2 y +3 Hay otra manera de almacenar los datos en un +3 cuando se utiliza con el compilador Hisoft Basic. El metodo anterior SAVE DATA (unica alternativa en el +3 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 versión que sigue a continuación, almacena cada elemento de la cadena separadamente y se detiene cuando los datos se acaban. 5 REM :int n,l 6 REM :open# 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 80 CLS : PRINT "Almacenando los datos" 100 INPUT "Tipea letra de unidad (a/b)";d$ 110 OPEN #4,d$+":fichero" 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 Nota: Una vez terminado, salvar y luego compilar pulsando primero INV.VID+TRU.VID. a la vez, y luego C por compilar. Pulsar una tecla en cada interrupcion hasta que termine la compilación y si todo ha salido bien, usar la opcion R, para ejecutar la compilacion. Al igual que antes se le pide al usuario que teclee la letra de la unidad. Esta version trabaja solo con discos. La línea 100 solicita que unidad de disco ('a' ó 'b') se desea y la línea 110 abre el canal de comunicaciones con el disco. Hisoft Basic 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, mientras las líneas REM son directivas requeirdas por el compilador. La version Hisoft Basic para cargar de nuevo los datos se parece a su procedimiento de escritura excepto de PRINT#, se pone INPUT# y las variables son separadas por pto. y coma para su correcta lectura: 5 REM :int n,l 6 REM :open# 200 DIM a$(50,15): DIM b$(50,15): DIM t$(50,12): DIM n(1) 205 INPUT "Tipea letra de unidad (a/b)";d$ 210 OPEN #4,d$+":fichero" 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 Nota: El programa no se ejecutará si falta la linea REM: open#. Nota 2: Para manejar ficheros, HISOFT Basic requiere que se le indique si el archivo es de lectura o escritura. Asi que en la linea 110 del listado para generar el archivo hay que modificarlo como sigue: 110 OPEN #4,"-"+d$+":fichero" mientras que para leerlo hay que hacer la sigte modificacion: 210 OPEN #4,"+"+d$+":fichero" De no modificar esas lineas, entonces solo quedar acordarse de tipear "-a" o "+a", "-b" o "+b" cada vez que pida que se elija el drive a usar. Hisoft Basic acepta tambien INKEY$# para leer los datos, caracteres uno a uno. 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 el +3 carece de una funcion EOF() que capture el final del fichero (pero como veremos luego, uno pude poner su propia marca muda). Al no haber EOF(), la unica forma de detectar el final de un fichero en el +3 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. En el +3, este ejemplo solo sirve si se tiene Hisoft Basic, que 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: 5 REM :int n,l 6 REM :open # 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 (a/b)";d$ 110 OPEN #4,d$+":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 5 REM :int n,l 6 REM :open # 200 DIM a$(50,15): DIM b$(50,15): DIM t$(50,12) 205 INPUT "Tipea letra de unidad (a/b)";d$ 210 OPEN #4,d$+":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 - Manejando ficheros con el +3e Por alguna razón Amstrad no dotó de facilidades paa manejar ficheros en +3 Basic. Solo es posible salvar matrices individuales, como ya se ha visto, a menos que uno usara el compilador Hisoft Basic, para corregir dichas limitaciones. Ahora era posible abrir y cerrar ficheros de texto OPRN/CLOSE y leer y escribir en ellos con INPUT#, INKEY$# y PRINT#, manteniendo una sintaxis simple y estandar. La unica limitación es que eran ficheros seriales (pese a que teoricamente el +3dos permite acceso aleatorio), y no hay como detectar el fin de fichero, a menos que uno lea los datos caracter por caracter mediante INKEY$, el cual devuelve la cadena vacía cuando llega al final de fichero. Esto solo funciona si uno trabaja con el programa compilado en el +3 y cara los pocos bytes extras de codigo suplido en un archivo llamado 'RUNTIME'. Ahora con el +3e, el uso del Hisoft Basic es opcional, ya que su nuevo DOS posee todas las facilidades para manejar ficheros tanto secuenciales como directos. +3e - Ficheros secuenciales Creacion de un fichero En el +3e, el nombre del fichero debe de cumplir los convenios del sistema operativo CP/M, siendo el nombre de 8 caracteres más el punto y la extension de máximo tres caracteres. Esta ultima es siempre opcional, pero ayuda a identificar mejor los datos. Nota: Para la explicacion de los comandos del +3edos, ver el manual del +e y +3e. Como ejemplo vamos a crear un fichero que contenga los numeros del 1 al 100: 100 OPEN #4,"O>num.dat" 120 FOR n=1 TO 100 130 PRINT #4; n 140 NEXT n 150 PRINT #4;CHR$ 0 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$ Lectura de un fichero +3dos carece de la sentencia INPUT#, debido a ello, los datos, pese a salvarse del modo normal con PRINT#, no pueden ser leidos más que caracter a caracter ya sea con INKEY$# o con una orden exclusiva del +3e-Dos llamado NEXT#. 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,"I>num.dat" 320 NEXT #4,n: LET n$=CHR$ n 330 IF n$=CHR$ 0 THEN GO TO 360 340 PRINT n$; 350 GO TO 320 360 PRINT "fin de fichero" 370 CLOSE #4 El ejemplo anterior leía todo sin separar los datos, encima lo hace leyendo todo como caracter alfanumerico, vamos a crear entonces una subrutina que reemplace a INPUT#, para recuperar la variable como numerica: 400 REM leyendo un fichero secuencial numerico 410 OPEN #4,"I>num.dat" 420 LET chn=4: GO SUB 9000: LET n=VAL a$ 430 IF a$=CHR$ 0 THEN GO TO 460 440 PRINT n 450 GO TO 320 460 PRINT "fin de fichero" 470 CLOSE #4 480 STOP 9000 LET a$="" 9010 NEXT #chn,cc 9020 IF cc=13 THEN RETURN 9030 LET a$=a$+CHR$ cc 9040 GO TO 9010 Ahora para leer datos separadamente, habría que llamar a la subrutina por cada variable de datos en el fichero, como muestra el siguiente ejemplo: 1000 OPEN #6,"O>prb.dat" 1010 PRINT #6;"prueba"'"#2","numero";128 1020 CLOSE #6 1050 OPEN #6,"I>prb.dat" 1060 LET chn=6: GO SUB 9000: LET n$=a$: GO SUB 9000: LET m$=a$: PRINT n$'m$ 1070 CLOSE #6 1075 STOP Añadiendo datos a un fichero secuencial No existe un modo APPEND en el +3e, pero hay hasta dos modos de añadirle nuevos datos a un fichero previamente salvado. APPEND - metodo 1: El primer metodo es leyendo la longitud del fichero antes de cerrarlo usando la orden RETURN# y salvandola en una matriz unidimensional con SAVE DATA. 1100 REM modo append 1110 OPEN #4,"O>num2.dat" 1120 FOR n=100 TO 0 STEP -1 1130 PRINT #4;n 1140 NEXT n 1145 DIM n(1): RETURN #4,n(1): SAVE "add1.n" DATA n() 1150 CLOSE #4 La rutina de lectura, que en vez de usar Open I>(input), abrirá con U>(update), debe cargar la longitud con LOAD DATA y usar GOTO# para mover el puntero hasta el final(*) a partir de donde se empezará a agregar los nuevos datos: 1210 OPEN #5,"U>num2.dat" 1215 LOAD "add1.n" DATA n(): GO TO #5,n(1) 1220 FOR n=1 TO 100 1230 PRINT #5;n 1240 NEXT n 1245 PRINT #5;CHR$ 0 1250 CLOSE #5 Esta vez los datos han sido salvados con una marca muda de EOF, a diferencia de antes. Para añadir más datos ahora, habría que modificar la rutina de lectura para que reconozca la marca muda y así no la añada al fichero con los futuros datos que se pondrán ya que entonces el fichero acabará con un montón de marcas mudas en diferentes partes de la misma, cosa que no deseamos que pase. (*) de lo contrario reiniciará el fichero desde cero, sobreescribiendo y eliminando todo lo antes salvado en vez de añadirle los nuevos datos. 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,"I>num2.dat" 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 Si bien he elegido leer con INKEYS$#, también puede ser leido mediante NEXT#: 1600 REM eof 2 1610 OPEN #5,"I>num2.dat" 1620 LET chn=5: GO SUB 9000: LET n=VAL a$ 1630 LET EOF=(a$=CHR$ 0): IF EOF THEN GO TO 1640 1635 PRINT n: GO TO 1620 1640 CLOSE #5 1650 STOP EOF - versión 2 En este caso en vez de usar una variable EOF, he elegido crear una FN E() por EOF(): 1410 DEF FN e(n$)=(n$=CHR$ 0) 1420 OPEN #5,"I>num2.dat" 1425 LET a$="" 1430 LET m$=INKEY$#5 1432 IF FN E(m$) THEN GO TO 1490 1435 IF m$ =CHR$ 13 THEN GO TO 1460 1440 LET a$=a$+m$ 1450 GO TO 1430 1460 LET n=VAL a$ 1470 PRINT n 1480 GO TO 1425 1490 CLOSE #5 1500 STOP APPEND - metodo 2: Tras definir el EOF, podemos pasar a ver la segunda forma de generar un modo APPEND, esta vez creando un fichero que cerramos con marca muda: 2000 REM modo append 2 2010 OPEN #4,"O>num3.dat" 2020 FOR n=1 TO 10 2030 PRINT #4;n 2040 NEXT n 2050 PRINT #4;CHR$ 0 2060 CLOSE #4 2070 STOP En vez de salvar la longitud para cargarla luego, definimos una subrutina para leer los datos hasta llegar a la marca muda y devolver la longitud que servirá para mover el puntero hasta el punto a partir del cual queremos añadir más datos: 2100 OPEN #5,"U>num3.dat" 2110 LET chn=5: GO SUB 9100: LET long=zz: GO TO #5,long 2120 FOR n=1 TO 10 2130 PRINT #5;n*2 2140 NEXT n 2150 PRINT #5;CHR$ 0 2160 CLOSE #5 2170 STOP Esta rutina 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 Una mejora es la sigte: 9110 LET EOF=(INKEY$ #chn=CHR$ 0): IF EOF THEN RETURN 9120 GOTO 9110 con lo que la linea 2110 pasaría a ser: 2110 LET chn=5: GOSUB 9100: RETURN #chn,long: GOTO #chn,long Incluso podemos redefinirla así: 9110 LET EOF=(INKEY$ #chn=CHR$ 0): IF EOF THEN RETURN #chn,long: GOTO #chn,long : RETURN 9120 GOTO 9110 de este modo la linea 2110 se reduciría a: 2110 LET chn=5: GOSUB 9100 Retomemos ahora el ejemplo de I - No lo olvides, archivalo, y convirtamoslo a +3e. Eliminamos las lineas 5 y 6 de HisoftBasic y la linea 110 pasaría a ser: 110 OPEN #4,"O>"+d$+":fichero" mientras la línea 210: 210 OPEN #4,"I>"+d$+":fichero" la linea de lectura sin INPUT# se verá: 230 LET chn=4: GO SUB 9000: LET a$(l)=a$: GO SUB 9000: LET b$(l)=a$: GO SUB 9000: LET t$(l)=a$ +3e - Ficheros de acceso directo Hasta ahora hemos visto cómo leer y añadir nuevos datos a un fichero secuencial. Pasamos pues a ver como trabajar con ficheros directos o aleatorios. El truco es con GOTO#, pero para comprender mejor como opera veamos el sigte ejemplo: 1800 OPEN #4,"O>dat2.num" 1810 PRINT #4; 100 1820 CLOSE #4 1830 STOP 1900 OPEN #4,"U>dat2.num" 1905 GO TO #4,4 1910 PRINT #4; 400'CHR$ 0 1920 CLOSE #4 1930 STOP RETURN# devuelve como valor, la cantidad de caracteres que puede tener en total el fichero o hasta donde se quiera leer con INKEY$# o NEXT#. En el ejemplo de ahora, tenemos que el valor salvado es 100 y que el GOTO# mueve el puntero a 4, es decir, que el numero fue salvado como una cadena de 3 digitos y por lo tan6to debemos de salvar cadenas de longitud fija para mover el puntero a donde queremos, de lo contrario leeremos los datos erroneamente. El sigte ejemplo lee el fichero del metodo 2 de APPEND, pero esta vez en modo directo: 2350 OPEN #4,"I>num3.dat" 2355 LET chn=4 2360 INPUT "Registro #:";reg: IF reg=-1 THEN GO TO 2380 2361 IF reg>10 THEN LET reg=reg+1 2365 GO TO #4,(reg-1)*2 2370 GO SUB 9000: LET n=VAL a$: PRINT n 2371 REM GO SUB 9000: PRINT a$ 2375 GO TO 2360 2380 CLOSE #4 2385 STOP Un fichero 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,"O>numx.rnd" 3020 FOR n=1 TO 10 3030 GO TO #4,(n-1)*4 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,"I>numx.rnd" 3115 LET chn=4 3120 FOR n=1 TO 10 3130 GO TO #4,(n-1)*4 3140 GO SUB 9000: LET n$=a$ 3150 PRINT n$ 3160 NEXT n 3170 CLOSE #4 3180 STOP 3200 REM modo rnd rd/wr 3210 OPEN #4,"U>numx.rnd" 3215 LET chn=4 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 GO TO #4,(reg-1)*4 3240 GO SUB 9000: LET n$=a$ 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 GOTO#. Pero resulta que el subindice empieza a partir de cero y no 1, lo cual hace que la formula sea: (indice - 1) * dim + 1, lo cual nos da el (n-1)*4 del ejemplo. Funciones MKI$ y CVI: +3e 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 ya que no hay ninguna version de BetaBasic para +3 y por ende el +3e, 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(... (*) (*)Estas funciones fueron publicadas dentro de una coleccion de 50 DEF FN en el foro de World of Spectrum. Ejemplos: 100 REM en el programa de escritura 110 DIM x$(2) 120 LET x$=FN C$(x) 100 REM en el programa de lectura 120 LET a=FN N(a$) Para terminar este articulo ofrezco este programa originalmente publicado en el manual del Timex FDD 3000, pero convertido para correr en el +3e: 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,"O>address.rnd": CLOSE #4 110 LET end=20000 115 OPEN #4,"U>address.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 GO TO #4,(n-1)*100 1015 LET chn=4 1020 GO SUB 9000: LET a$=q$ 1930 RETURN 2000 REM //escribe fichero// 2005 GO TO #4,(n-1)*100+1 2010 PRINT #4;n$+b$+p$+c$ 2020 RETURN 9000 REM //input #// 9010 LET q$="" 9020 NEXT #chn,cc 9030 IF cc=13 THEN RETURN 9040 LET q$=q$+CHR$ cc 9050 GO TO 9020 Nota: el único problema para manejar archivos de este tipó con +3e, es que al no tener la sentencia INPUT#, se hace mas lenta su lectura ya que lo hace caracter por caracter uno a uno hasta llegar al final del fichero. Una alternativa seria reemplazando la instruccion NEXT# o INKEY$# por una rutina en Codigo Maquina que si equivalga a INPUT#. Francisco Leon zx_if1@hotmail.com