RELATIVE FILE TUTORIAL ( Part 2 ) In our last issue we examined some of the basic fundamental of Relative Files and some of the ways which they can be used . This month we will wrap up the tutorial with a " learn by doing " technique which I hope will clear up any questions you may have at this point ! I would like to remind you all that if you want to learn more about this or any other subject, please do not hesitate to contact the education co - ordinators about your areas of interest ! After all, learning in a classroom setting is much more rewarding ! A PROGRAM TO CREATE A RELATIVE FILE The following program will create a relative file for you . If the file may be large, its best to use a completely blank disk for it, and another disk for your programs . This program will ask you for the name of the file and the record length . 10 INPUT " FILENAME "; F $ 20 INPUT " RECORD SIZE "; R % 30 OPEN 15,8,15 40 OPEN 2,8,2,F $+", L ,"+ CHR $( R %+ 1 ) 50 INPUT " LASTRECORD "; N 60 RH %= N / 256 : RL %= N -( RH %* 256 ) 70 PRINT # 15 ," P "+ CHR $( 2 + 96 ) NN + CH R $( RL %)+ CHR $( RH %)+ CHR $( 1 ) 80 PRINT # 2 ," ENDOFFILE " 90 INPUT # 15,E,E $, T,S : PRINTE,E $ 100 CLOSE1 : CLOSE15 A PROGRAM TO PRINT OUT A RELATIVE FILE Here ' s a program to print the contents of the relative file you created to the screen . Just provide the file name . Note that the program keeps reading records until it hits error 50 RECORD NOT PRESENT . This is an easy way to determine when all of the records have been read . 10 OPEN15,8,15 20 INPUT " FILE NAME "; F $ 30 OPEN2,8,2,F $ 40 N = 0 50 N = N + 1 60 GOSUB 1000 70 PRINT # 15 ," P " + CHR $( 2 ) + CHR $( RL %) + CHR $( RH % ) + CHR $( 1 ) 80 GOSUB 2000 90 IF E = 0THEN INPUT # 2,A $: PRINT " RECORD "; N " :"; A $: GOTO50 100 CLOSE2 : CLOSE15 : END 1000 RH %= N / 256 : RL %= N -( RH %* 256 ): RETURN 2000 INPUT # 15,E,E $, T,S : RETURN WRITING AND READING RECORDS Writing records is accomplished using the PRINT # command . It works just like the normal PRINT command, except that the output goes to a file instead of the screen . The format is : PRINT # file number,variable list . For example, in the first program the line PRINT # 2 ," ENDOFFILE " will write the character string " END OF FILE " with a carriage return to logical file number 2 . The PRINTcommand sends output to the file EXACTLY the same way PRINTwould send output to the screen . Numbers are output with a leading minus or space, and with a trailing blank . A carriage return character will be written whenever an end - of - basic - line or a colon is encountered . Writing a record to a relative file is usually done by concatenation all of the fields in a record into one large character string and then writing the string to the file . There are 2 ways to read records from the file . INPUT # works just like the INPUT statement, except that it retrieves the data from a file instead of the keyboard . The format is : INPUT # file number, variable list . The other way is with the GET # statement, which retrieves a single character from the file . Its format is : GET # file number,Character variable . THE 2 WAYS OF FORMATTING RECORDS . There are 2 main ways of structuring the fields that make up records in the file . The first way is to use fixed length fields, concatenate the fields together into one string, and then write the string to the file . To read the records back in, the GET # statement would be used in a loop to read all of the characters in the record, and then the MID $ string function could be used to break the record up back into the original fields . For example we could construct the record and write it like this,using R $ as the record variable . R $= A $+ B $+ C $+ D $ PRINT # 2,R $ To read the record back in, assuming a record length of 50 bytes . R $="" FORI = 1TO50 : GET # 2,C $: R $= R $+ C $: NEXT Finally, the record fields could be extracted like this, assuming 4 fields with fixed lengths of 10,20,10,and 10 bytes : A $= MID $( R $, 1,10 ) B $= MID $( R $, 11,20 ) C $= MID $( R $, 31,10 ) D $= MID $( R $, 41,10 ) If the data we are assigning into a field is smaller than the field size, it must be padded with blanks . This is accomplished with the LEFT $ function . The data is concatenated with a blank string the size of the field, and then the overflow is truncated . N For example the data " MIKE " could be assigned into a 10 character name field like this : S $="" N $=" MIKE " R $= R $+ LEFT $( N $+ S $, 10 ) The second method is to use variable size fields, and is based on the fact that INPUT # has some restrictions on how it can be used . INPUT # looks for SEPARATORS, which can be either a comma or a carriage return character . The largest string that INPUT # can read before encountering a separator is 88 characters . Remember, INPUT # behaves EXACTLY the same way as the standard INPUTstatement . When you use the INPUT statement and type data at the keyboard, you separate individual data with carriage returns or commas . Since the only difference with INPUT # is that the source of the data is a file instead of the keyboard, the data has to be written to the file in a manner that INPUT # can read back . With this second method of formatting records, the fields are separated by separators like a carriage return, so that INPUT # can then read them back in . Since the carriage return character is CHR $( 13 ), we can do the following : CR $= CHR $( 13 ) R $= A $+ CR $+ B $+ CR $+ C $+ CR $+ D $+ CR $ PRINT # 2,R $ Since we ' ve used field separators, reading the record back in is easy : INPUT # 2,A $, B $, C $, D $ By formatting records this way, we can make variable size fields, and since we have used the carriage return to separate the fields, the INPUT # statement will break up the record for us automatically into its fields when it is read back in . WHICH METHOD TO USE Due to the limitation of the INPUT # statement, you must use the first method when the field lengths may be longer than 88 characters . This method also saves memory by eliminating separator characters . The disadvantage of this method is that you have to read the records using the GET # statement, which is slower than INPUT #. In addition, you must pad all of the fields with blanks if they are smaller than the field size, so that you completely fill up the record . The second method should be used when you want the fields to be of varying size . The disadvantage of this method is that the separator characters each take up a byte in the record . You must take them into account when determining the record length . AN EXAMPLE This example will involve a very simple address file, which contains only 3 fields : A person ' s last name, first name, and the town that they are from . The first program will use fixed length fields and will have field lengths as follows : LASTNAMEN : 15 characters FIRST NAME : 15 characters TOW NN : 20 characters This gives a total record length of 50 characters . Use the first program in this tutorial to create a file called NAMES1 with a record length of 50 characters . The second program will allow variable field lengths . Allowing 2 bytes for field separators gives us 52 bytes as the record length . The 3 fields can each vary in length,but their total length will still be 50 bytes . Create another relative file called NAMES2 with a record length of 52 characters . The two programs that follow will allow you to read and write records to relative files, the first program with fixed field length records and the second program with variable field length records . FIXED FIELD LENGTH PROGRAM EXAMPLE 10 S $=" ": rem20 spaces 20 INPUT " FILENAME "; F $ 30 OPEN15,8,15 : OPEN2,8,2,F $ 40 PRINT 50 PRINT " ENTER W TO WRITE A RECORD " 60 PRINT " ENTER R TO READ A RECORD " 70 PRINT " ENTER Q TO QUIT " 80 INPUTO $: IF O $<>" W " AND O $<>" R " AND O $<>" Q " THEN40 90 IFO $=" W " THEN GOSUB1000 : RETURN 100 IFO $=" R " THEN GOSUB2000 : RETURN 110 CLOSE2 : CLOSE15 : END 1000 INPUT " RECORD NUMBER "; N : RH %= N / 256 : RL %= N -( RH %* 256 ) 1010 INPUT " LAST NAME "; LN $ 1020 INPUT " FIRST NAME "; NA $ 1030 INPUT " TOWN "; T $ 1040 R $="" 1050 R $= R $+ LEFT $( LN $+ S $, 15 ) 1060 R $= R $+ LEFR $( NA $+ S $, 15 ) 1070 R $= R $+ LEFT $( T $+ S $, 15 ) 1080 PRINT # 15 ," P "+ CHR $( 2 + 96 ) + CHR $( RL %)+ CHR $( RH %)+ CHR $( 1 ) 1090 PRINT # 2,R $ 1100 RETURN 2000 INPUT " RECORD NUMBER "; N : RH %= N / 256 : RL %= N -( RH %* 256 ) 2010 PRINT # 15 ," P "+ CHR $( 2 + 96 ) + CHR $( RL %)+ CHR $( R H %)+ CHR $( 1 ) 2020 IFE <> 0THENPRINT " RECORD DOES NOT EXIST ": RETURN 2030 R $="" 2040 FORI = 1TO50 : GET # 2,C $: R $= R $+ C $: NEXT 2050 LN $= MID $( R $, 1,15 ) 2060 NA $= MID $( R $, 16,15 ) 2070 T $= MID $( R $, 31,20 ) 2080 PRINT 2090 PRINT " LAST NAME :"; LN $ 2095 PRINT " FIRST NAME :"; NA $ 2100 PRINT " TOWN :"; T $ 2110 RETURN 3000 INPUT # 15,E,E $, T,S : RETURN VARIABLE LENGTH FIELDS PROGRAM EXAMPLE 10 CR $= CHR $( 13 ) 20 INPUT " FILENAME ": F $ 30 OPEN15,8,15 : OPEN2,8,2,F $ 40 PRINT 50 PRINT " ENTER W TO WRITE A RECORD " 60 PRINT " ENTER R TO READ A RECORD " 70 PRINT " ENTER Q TO QUIT " 80 INPUT O $: IF O $<>" W " AND O $< >" R " AND O $<>" Q " THEN 40 90 IFO $=" W " THEN GOSUB1000 : GOTO40 100 IFO $=" R " THEN GOSUB2000 : GOTO40 110 CLOSE2 : CLOSE15 : END 1000 INPUT " RECORD NUMBER "; N : RH %= N / 256 : RL %= N -( RH %* 256 ) 1010 INPUT " LAST NAME "; LN $ 1020 INPUT " FIRST NAME "; NA $ 1030 INPUT " TOWN "; T $ 1040 R $="" 1050 R $= LN $+ CR $+ NA $+ CR $+ T $ 1060 PRINT # 15 ," P "+ CHR $( 2 + 96 )+ CHR $( RL %) + CHR $( RH %)+ CHR $( 1 ) 1070 PRINT # 2,R $ 1080 RETURN 2000 INPUT " RECORD NUMBER "; N : RH %= N / 256 : RL %= N -( RH %* 256 ) 2010 PRINT # 15 ," P "+ CHR $( 2 + 96 ) + CHR $( RL %)+ CHR $( R H %)+ CHR $( 1 ) 2020 GOSUB3000 : IFE <> 0 THENPRINT " RECORD DOES NOT EXIST ": RETURN 2030 INPUT # 2,LN $, NA $, T $ 2040 PRINT 2050 PRINT " LASTNAME :"; LN $ 2060 PRINT " FIRST NAME :"; NA $ 2070 PRINT " TOWN :"; T $ 2080 RETURN 3000 INPUT # 15,E,E $, T,S : RETURN That ' s all for now ! :)