Liberty Basic is develeopped by Carl Gundel
Original Newsletter compiled by Alyce Watson and Brosco
Translation to HTML: Raymond Roumeas

Brosco's Liberty Basic Newsletter - Issue #9 - June 98

 
 

In this issue:

  1. Using Random files - Part 1

Ok - lets first understand what a RANDOM file is.

Basically all files (including text files) are RANDOM files! Its just a stream of data that you can start reading anywhere - rather than at the first position - and you retrieve records of data rather than text strings.

Within LB, life has been simplified for us. We can tell LB that we have a record or structure for the data, and it gets it for us. If you were accessing a file as random in some other Windows programming languages you would need to keep track of the record length and request a specific number of bytes and the byte starting position within the file - with LB we simply tell it the record number that we want to read or write.

Here's a very simple example of using a Random file in LB. Suppose that we wanted to create a catalogue of our collection of Video Cassettes. Each cassette has a number on its label, starting with 0001 and incrementing as we add to our collection - it will be OK if some numbers are missing. We will keep track of the Movie name and the main star in the movie. The first program will record a couple of cassettes that are already in our collection.

nomainwin
    open "video.txt" for random as #f len=52    '*** note 1
    field #f, _
        4 as cNum, _
        24 as name$, _
        24 as mainActor$
 
    cNum = 1
    name$="Golden Eye"
    mainActor$ = "Pierce Brosnan"
    put #f, 1
 
    cNum = 3
    name$ = "Ransom"
    mainActor$ = "Mel Gibson"
    put #f, 3
 
    close #f
 
    notice "Initial database has been created"
    end
 
***** Note 1 

First of all - read the second statement of the program very carefully! On the end of the OPEN statement there is "len=49". This is the length of the record. This must EXACTLY match the total length of all FIELDs specified in the next statement.

The file has been given a name of "video.txt" - you could choose any name you liked - plus the extension could be any name you wanted. I used the extension of .TXT so that you could run the program and then, using Windows Explorer - simply double click on the file and Notepad would display the contents of our database. Please do this now - 'cut' the program above - 'paste' it into LB and then run it.

Then use Notepad to examine the contents of "video.txt".

When you view the file, click on EDIT and then WORDWRAP so that you can see all the data. Notice that we added record #1 and then record #3. LB inserted a blank record #2 for us.

Also note that the cassette number (cNum) is displayed as text, even though its a number within our program - LB does that for us. All data in our database is stored as text - and converted to the correct format for use in the program.

Next, we will have a very simple program to list the contents of our database:

open "video.txt" for random as #f len=52 
field #f, _
4 as cNum, _
24 as name$, _
24 as mainActor$
for i = 1 to 3
get #f,i
print cNum;" ";name$;mainActor$
next i
notice "Initial database has been displayed"
 
close #f
end
 

Cut and Paste this program to LB and run it. You will see the contents listed.

Now that we have seen how easy it is to read and write to random files - lets build a slightly more realistic program to add, update, delete and browse our database.

 
' Sample program to update a database
' Brosco - June 98 (Newsletter #9)
'
    open "video2.txt" for random as #f len=49
    field #f, _
        1 as active$, _
        24 as name$, _
        24 as mainActor$
 
    nomainwin
    WindowWidth = 320
    WindowHeight = 230
 
    statictext #w.1, "Cassette Number:", 10, 40, 130, 20
    statictext #w.2, "Movie Name:", 10, 70, 130, 20
    statictext #w.3, "Main Star:", 10, 100, 130, 20
 
    statictext #w.4, "Status:", 10, 175, 65, 20
    statictext #w.status, "", 80, 175, 240, 20
 
    textbox #w.cn, 150, 40, 30, 25
    textbox #w.movie, 150, 70, 150, 25
    textbox #w.star, 150, 100, 150, 25
 
    button #w.add, "Add", [add.movie], UL, 70, 140, 50, 25
    button #w.upd, "Update", [update.movie], UL, 130, 140, 50, 25
    button #w.del, "Delete", [delete.movie], UL, 190, 140, 50, 25
    button #w.exit, "Quit", [close.w], UL, 250, 140, 50, 25
 
    button #w.prev, "<--Prev", [previous], UL, 70, 5, 60, 25
 
    button #w.next, "Next -->", [next], UL, 160, 5, 60, 25
 
    button #w.default, "Get", [get.movie], UL, 10, 140, 50, 25
 
    open "Movie Database" for dialog as #w
    print #w, "trapclose [close.w]"
    print #w.cn, "!setfocus"
 
[loop]
    input var$
    goto [loop]
 
[previous]
    cNum = cNum - 1
    if cNum < 1 then
        cNum = 1
        print #w.status, "You are at the start of the database"
        goto [loop]
        end if
    get #f, cNum
 
    if active$ <> "1" then [previous]
    gosub [display.movie]
    goto [loop]
 
[next]
    cNum = cNum + 1
    if cNum > lof(#f) / 49 then
        cNum = lof(#f) / 49
        print #w.status, "You are at the end of the database"
        goto [loop]
        end if
    get #f, cNum
    if active$ <> "1" then [next]
    gosub [display.movie]
    goto [loop]
 
[display.movie]
    print #w.cn, cNum
    print #w.movie, name$
    print #w.star, mainActor$ 
    print #w.status, ""
 
    print #w.cn, "!setfocus"
    return
 
[get.movie]
    print #w.cn, "!contents?"
    input #w.cn, cNum
    if cNum < 1 then
        notice "Get error!" + chr$(13) + _
            "Cassette number must be greater than 0"
        goto [loop]
        end if
    if cNum > lof(#f) / 49 then    'check if the record exists
[get.error]
        notice "Get Error!" + chr$(13) + _
            "This record doesnt exist"
        goto [loop]
        end if
    get #f, cNum
 
    if active$ <> "1" then [get.error]
    gosub [display.movie]
    goto [loop]
 
[add.movie]
    print #w.cn, "!contents?"
    input #w.cn, cNum
    if cNum < 1 then
        notice "Add error!" + chr$(13) + _
            "Cassette number must be greater than 0"
        goto [loop]
        end if
    if cNum <= lof(#f) / 49 then    'check if the record exists
        get #f, cNum    'check if the record is active
        if active$ = "1" then
            notice "Add error!" + chr$(13) + _
 
                "This Cassette exists in the database." + chr$(13) + _
                "Select GET - then Update"
                goto [loop]
                end if
        end if
    gosub [write.record]
    print #w.status, "Movie has been added."
    goto [loop]
 
[update.movie]
    print #w.cn, "!contents?"
    input #w.cn, cNum
    if (cNum < 1) or (cNum > lof(#f)/49) then
[update.error]
        notice "Add error!" + chr$(13) + _
            "Cannot update non-existant record."
 
        goto [loop]
        end if
    get #f, cNum
    if active$ <> "1" then [update.error]
    gosub [write.record]
    print #w.status, "Movie has been updated."
    goto [loop]
 
[delete.movie]
    print #w.cn, "!contents?"
    input #w.cn, cNum
    if (cNum < 1) or (cNum > lof(#f)/49) then
[delete.error]
        notice "Delete error!" + chr$(13) + _
            "Cannot delete non-existant record"
        goto [loop]
        end if
    get #f, cNum
    if active$ <> "1" then [delete.error]
 
    active$ = ""
    name$ = ""
    mainActor$ = ""
    put #f, cNum
    gosub [display.movie]
    print #w.status, "Movie has been deleted."
    goto [loop]
 
[write.record]
    print #w.movie, "!contents?"
    input #w.movie, name$
    print #w.star, "!contents?"
    input #w.star, mainActor$
    active$ = "1"               ' show the entry is valid
    put #f, cNum
    return
 
[close.w]
    close #w
    close #f
    end

Cut and Paste the above program to the LB editor and then run the program.

A very good way to see how a program works is to use LB's Debug mode and Step through the program.

Some notes about this program.

Instead of storing the CassetteNumber in the database, we used that as the physical record number in that database. That is, if you add Cassette 0010, we will write the record in position 10 of the database.


You will notice a new field has been added to FIELD - called "active$". When we write a valid record to the database, we set it to "1". When LB writes blank records, or when we delete a record, it is set to " ". This way we know which records are valid.
You will see several refences in the code like:

if cNum > lof(#f) / 49 then

lof(#f) returns us the length of the file (in bytes). By dividing by 49 - the length of the FIELD structure, we know how many records exist on the database. We need to know this so that we dont try to GET non-existant records - that would cause an error and crash the program.

***********

OK - so what's wrong with this program?

1) First the KEY to the database must be a number, and unless we want to create a very large file, the keys should start at 1 and have very few 'gaps'.

2) To re-use deleted space - we must know the available record numbers.

3) If we wanted to find all the movies that starred our favourite actor, we would have to scan the entire database.

Next issue I will address these issues and, hopefully I will also have the problems in my DBDLL sorted out so that we can add a very fast indexing access method.

If you would like to discuss any of the code or techniques used here, please use my message board at:

http://users.orac.net.au/~brosco

and ideally, include "NL0009" is the Subject of the posting.

Also see - Using Random files - Part 2

Also see - Using Random files - Part 3


Newsletter written by: Brosco. Comments, requests or corrections to: brosco@orac.net.au Translated from Australian to English by an American: Alyce Watson. Thanks Alyce.