A Random Access File for Your Personal Address Book

By Welopez

Complete BAS and data file can be downloaded from Personal Address Book.

The Worble in charge of my data files paid another visit to me this week. You remember Ophelia Packerschnozz, don't you? She's the Worble who helped me create a sequential data file for use as a check register. [http://justbasic.conforums.com/index.cgi?board=tutorial&action=display&num=1118431436]

"I see you're trying to create an application to use as a personal address book, Welopez. You're having trouble with the random access file?"

"Well, yes," I acknowledged. "I'm pretty well hip on sequential data files, thanks to your help, but random access files are horses of a different feather to me." It never hurts to be friendly and polite when a Worble offers to assist you with programming problems.

"Horses don't have feathers, Welopez!"

"Hmmm, maybe that's my problem? What exactly is a random access file and how do I use it?"

"Since you're so fond of smilies, why don't you just think of a random access file like Dorothy on 'The Yellow Brick Road?'"

"How's that?" I asked. I didn't have to put on my stupid-hat, when it comes to files it's permanently emplaced on my head.

"Data files contain one or more fields which you can address individually when you work in your program. Fields can be numeric or string, depending upon how you write the program and save your data to the file. In a sequential data file, each field is usually separated from the next using a comma as the field delimiter. Just Basic allows you to specify a different field delimiter in the event you must have a comma contained in the field. Perhaps you want to save name$ and need to provide for Tom Smith, Jr, or Jack Jones, III.."

"Okay, Ms. Packerschnozz, I follow you so far. Fields in a sequential file are commonly separated by a comma, no pun intended."

The matron ignored my weak attempt at humor. "When you create a random file, you must specify what information will be contained in the file, the length of a record, and the length of each field making up the record. Each field is like a brick in that 'Yellow Brick Road,' and the program keeps track of finding the field you're searching for by knowing the length of each record, and the length of each field in the record. If the truth be known, there are no line feeds or carriage returns in a random access file. The entire file is simply one string of text and the only spaces are those which may be in the field, or spaces used to pad a short data entry to fill the length of the field specified."

"I read that in the help file, and so I began my code like this," I said, showing her.

OPEN "myContacts.txt" FOR RANDOM AS #book LEN=189
FIELD #book,_
30 AS name$,_
30 AS addr1$,_
30 AS addr2$,_
30 AS city$,_
3 AS state$,_
12 AS zip$,_
14 AS phone$,_
40 AS email$

"I can see you put some thought into that, Welopez, even if you made an error or two. The sum of all fields is 189, which gives a LEN=189 for each record. Not many people have names more than 30 characters long, but what if Athelwaite Duquesne Smythe-Brookfield is going to be in your address book? His name requires 37 characters and the last 7 won't be added to the file?"

"I'll just drop 'Duquesne,' it's a silly name anyway."

"Well, that will work, but your millionaire uncle Robert Duquesne might cut your friend out of the will, or you could have allowed 40 or 50 characters for the name. Your addr1$ and addr2$ should be adequate, unless the street name is exceptionally long. 30 characters for city$ will even accept 'City of Industry' in California.

"Next, you've allowed for as many as 12 characters in the zip code, but without the $ identifier, it can only be saved as a numeric value. If your user enters a nine digit zip code, 12345-6789, only the first 5 characters will be saved because the hyphen is a non-numeric character. The same applies to your phone numbers. If your user enters (555) 123-4567, nothing will be saved because the first character is non-numeric."

"Oh, I didn't know that. If I add the $ to the variable name, will that work?"

"Now you've got the idea, Welopez! I like to CLOSE all files the very moment I've finished with them, and OPEN them when I next need them, so I'd recommend you put your file open routine into a SUB so you won't have to type it everytime you need it again."

I added the $ needed to access zip$ and phone$ and then began writing the rest of the code, including a sub-routine to open my random access file only when needed. My idea to use a COMBOBOX to list all the people in my address book bombed right off the bat! "What did I do wrong, Ms. Ophelia?"

"A COMBOBOX must load the list into an array, Welopez. You're trying to put each record into the list, without concatenating the individual fields. You don't need all that extra information just wasting memory anyway. You don't have any index for the array, and if you sort the names alphabetically to make them easier for your user to find, the element numbers for the array will not be the same as the record numbers in your book."

"You mean I can't use a random access file for my COMBOBOX?"

"Sure you can, you just have to be as smart as a Worble, which is stretching things a little in your case. Suppose you are a stock broker, and you have 2,500 clients, each with 1 to 20 different stocks in their portfolio. Or suppose you are managing a products and parts inventory for a mail order business, you probably won't have enough memory in your computer to load all the data into an array and work with it. Remember, there was a time when computers were limited to a 64kb ceiling for RAM, and random access files were invented so you can work with individual records and not have to load the entire file into memory. So I'm going to load your array with only the name$ and record number, which will require much less RAM. Even if you had a million records, the average home computer could still hold an array of name$+nrRec, so we won't be stretching things.

"Your address book has only a few entries now, but if you are the club secretary for a bowling league, you might have several hundred. So we'll load only the name$, which has first and last name into our array. We're going to sort this array, so we'll add 10 SPACE$ to the name$ and then insert the number of the record. The SPACE$ will insure the number doesn't appear in the COMBOBOX list, but we can still use the number to GET the appropriate record from the file." The Schnozz added a few lines of code to my program and it looked like this:

'===== Count records in file and DIM entry$() array
SUB doPrep byref msg1$, byref nrRec
nrRec=LOF(#book)/189
msg1$="Address book contains "; nrRec; " records."
DIM entry$(nrRec)
FOR k=1 TO nrRec
    GET #book, k
    entry$(k)=name$+SPACE$(10)+STR$(k)
NEXT k

"entry$(k) is the array holding the list for your COMBOBOX, k is the number of the record in the file, name$ if the persons name, to which we add SPACE$(10), and then append k as a string. Next we'll sort entry$() array with this code:

'===== Sort entry$() array
FOR i=1 TO nrRec
    FOR k=1 TO nrRec-1
    IF entry$(k) > entry$(k+1) THEN
        temp$=entry$(k)
        entry$(k)=entry$(k+1)
        entry$(k+1)=temp$
    END IF
    NEXT k
NEXT i
END SUB

"For your address book, a bubble sort will be adequate. If you need to use a faster sorting algorithm, insert any you choose. There are many sorts which can be downloaded from the Internet, including the JB users board."

"I've written this sort to key on the value of name$, first name, last name, but you could use WORD$(name$, 2) if you wanted to sort the list keying on the last name. Just make sure you don't have any middle names among your contacts, or you'll throw off the sort. The Army uses NMI to indicate 'no middle initial,' and if you use it consistently you can sort by WORD$(name$, 3) to have the list ordered according to last name."

"Sheesh! Working with files is harder than I thought, Ms. Packerschnozz!"

"I've known you for several years, Welopez, and chewing bubble-gum is harder than you think!"

I ignored the dig, especially since it was true, while she kept looking over the code I had written. "Why did you enter the same 28 lines of code in two places just to open an identical window, Welopez? Haven't you ever heard of using a SUB or GOSUB?"

She modified my code to put the window definition into a GOSUB. Truthfully, I knew my code looked ugly, but when my user clicked the COMBOBOX to choose a person, I wanted the window to open with all the user information shown, and when I clicked the button to add a new entry, I wanted the window to open with blank fields. The problem was further complicated if I wanted to edit the persons information and save the record, or save the data fields as a new record. I kept getting errors which crashed my program! After Ms. Ophelia defined my 'generic' window in a GOSUB, the errors disappeared! How awesome! She's a smart woman, even for a Worble!

"Look at this code now. The [addRec] block sets a flag to tell us this is a new record to be added to the file and does not yet have a record number. The [showInfo] block retrieves the information for this person, by getting the record number we appended to name$ when we loaded entry$() array. When we click [addRec], we GOSUB [recWindow] to open the window with all data fields blank. When we click 'Save' in the same window, we use an IF/THEN comparison in [saveRec] to determine if we want to save the edited changes of an existing record, or save the data of a new record."

I tried several trial runs with the "new and improved" personal address book. Shazaam! Everything worked just as Ms. Ophelia promised! For joy! For joy! I'm a happy camper now! Oops….

"Ms. Ophelia," I timidly asked, "there doesn't seem to be any way to delete entries in this address book?"

"Oh, did I leave out something you have to learn on your own, Welopez? Shame on me! Why don't you think about the problem until next month? I'll be back to see how you've done."

Well, she did help me out quite a bit, I guess I shouldn't complain. Now where did I lay that help file… this is gonna take a little work!