Post by Rod on Apr 29, 2021 11:04:42 GMT
This is the link to uncleBen's original post.
jbfilesarchive.com/phpBB3/viewtopic.php?p=704#p704
Here is what uncleBen had to say about his code from the wiki archive.
Random access files with arrays
Why this library:
Here you'll find a number of functions that you can use as an alternative to ordinary random mode file I/O. The main difference is that here a single array is used for all the fields of a record. Apart from that the functions are designed to behave similarly to ordinary random access file I/O: fields that are shorter than the specified length of that field are padded with spaces, fields that are longer are truncated.
The main motivation to create these functions is that JustBASIC does not allow the following syntax:
open someFile$ for random as #f len = m
However, having to use a separate string for each field makes it hard to process record entries using loops. Especially if a record contains a lot of fields, this may force the programmer to use lots and lots of code lines, where an array would allow to write just a three-line loop.
If arrays could be used instead, you wouldn't have meaningful names for individual fields and it would be up to you to know what kind of data for example A$(4) contains, but on the positive side, you could in some cases greatly reduce the amount of code needed, and therefore also the number of potential typos and bugs.
General notes:
All the functions in this collection use two arrays: RecordField$(n) and FieldLength(n). It is the programmers responsibility do DIM these arrays at the beginning of the program. They will be automatically REDIMmed in the OpenRandomFile function.
RecordField$(n) represents strings for individual fields in a record. Just as with ordinary random access I/O, you'd assign string values to RecordField$(1) - RecordField$(n) (where n is the number of fields you have declared) before calling the PutRecord function, and this is where the results of a GetRecord call are stored.
FieldLength(n) should be used and modified only by the functions. You should not modify its values yourself. If you need, you can find some additional information from it: FieldLength(0) stores the number of total fields in one record, FieldLength(n+1) stores the size of one record in bytes/characters (it can be accessed like that size = FieldLength(FieldLength(0)+1) but there should be no practical need to do so.
Before using any of the functions OpenRandomFile should be called first. Only one file can be open at a time (since arrays are global).
Before the program ends or before opening another file CloseRandomFile must be called.
In a GUI database program, it is OK to open the database file at the beginning of the program, and not close it until in the trapclose branch.
Although most of these functions perform some sort of error checking (to prevent attempts to write or read beyond end of file) and return 0 if this should happen, you should not rely on this feature. As a good programmer it is your task to make sure that all those functions return 1 (success, no eof error).
Of course, no error checking can prevent misuse of the functions and coding errors.
All these functions may be used without restrictions. You may modify them to suit your needs, or use them as they are.
A source file containing the whole collection and examples of its usage, can be downloaded at Just Basic Files Archive
Main functions:
function OpenRandomFile(fileName$, fieldLengths$)
This function opens file called fileName$ for random access file I/O. The second argument is a string containing the length of each field separated by a space. The function returns the total number of records in the file.
So OpenRandomFile("mydata.dat", "16 8 2") opens "mydata.dat" and sets up 3 fields: 16 characters, 8 characters and 2 characters respectively. You can now use RecordField$(1)...RecordField$(3).
sub CloseRandomFile:
This sub closes the file opened with OpenRandomFile. Remember to call it before the program ends.
function PutRecord(no):
This function saves the current contents of RecordField$( in the file as record number no. The function returns 1 if successful, or 0 if it failed because no would have been beyond end of file.
function GetRecord(no):
This function reads record number no from the file and writes it to array RecordField$(. The fields are automatically trimmed of all padding whitespace. The function returns 1 if successful, or 0 if no was beyond end of file.
Additional functions:
In addition to the above main functions, there are several additional functions available. These functions are designed to facilitate some common tasks with database file I/O.
function FindRecord(key$, fieldNo, startFrom, mode$):
This function returns the number of the first record where key was found, or 0 if there were no matches.
The parameters are:
key$ - string to look for
fieldNo - number of the field to search in. (This number, of course, must not be larger than the total number of fields in a record.)
startFrom - number of the first record to start search with.
If you want to search from the beginning of the file, this value must be 1.
If, for example, you have found one match and want to continue with the rest of the file, this value should be (match+1).
mode$ - string specifying the search mode. Modes are:
"matchcase" or "" - find exact match, case sensitive search
"nomatchcase" - find exact match, not case sensitive search
"partial" or "partial matchcase" - find partial match (key$ is a substring of a field), case sensitive
"partial nomatchcase" - same as previous, except not case sensitive
E.g, n = FindRecord("John", 2, 14, "") searches for an exact match to "John" in field #2, starting from record #14.
Note: this function calls the GetRecord function, which must be included.
function GetField$(recordNo, fieldNo):
This function returns a string with a single field from record number recordNo. Unlike other functions it does not perform error checking.
function PutField(putWhat$, recordNo, fieldNo):
This function is for saving (modifying) the contents of one field only. Field number fieldNo of record recordNo is overwritten with the contents of putWhat$. The string is is padded or truncated as needed. The function returns 1 for success or 0 for failure.
function EraseRecord(no):
This function overwrites record number no with spaces, thus erasing it's contents, and returns 1 for success or 0 for failure.
Note: it does not remove the record from the disk, therefore a call to this function does not reduce the total number of records in the file.
function FindEmptyRecord():
This function returns the number of the first empty record in the file, or 0 if there are no empty records.
Note: if the database application provides means to delete records, then over time the file may contain several empty records. To conserve disk space in this case it would be recommended to add a new record to the end of the file only if there are no empty records in the file, otherwise those unused spaces could be overwritten instead.
function FieldsFit():
This function can be used before saving a record to check if any of the fields would be truncated, in which case users could be warned about data loss. The function returns 0 if no fields would be truncated, or the number of the first field that doesn't fit into the file and needs to be truncated.
jbfilesarchive.com/phpBB3/viewtopic.php?p=704#p704
Here is what uncleBen had to say about his code from the wiki archive.
Random access files with arrays
Why this library:
Here you'll find a number of functions that you can use as an alternative to ordinary random mode file I/O. The main difference is that here a single array is used for all the fields of a record. Apart from that the functions are designed to behave similarly to ordinary random access file I/O: fields that are shorter than the specified length of that field are padded with spaces, fields that are longer are truncated.
The main motivation to create these functions is that JustBASIC does not allow the following syntax:
open someFile$ for random as #f len = m
field #f, 16 as A$(1),_
16 as A$(2),_
...
16 as A$(n)
However, having to use a separate string for each field makes it hard to process record entries using loops. Especially if a record contains a lot of fields, this may force the programmer to use lots and lots of code lines, where an array would allow to write just a three-line loop.
If arrays could be used instead, you wouldn't have meaningful names for individual fields and it would be up to you to know what kind of data for example A$(4) contains, but on the positive side, you could in some cases greatly reduce the amount of code needed, and therefore also the number of potential typos and bugs.
General notes:
All the functions in this collection use two arrays: RecordField$(n) and FieldLength(n). It is the programmers responsibility do DIM these arrays at the beginning of the program. They will be automatically REDIMmed in the OpenRandomFile function.
RecordField$(n) represents strings for individual fields in a record. Just as with ordinary random access I/O, you'd assign string values to RecordField$(1) - RecordField$(n) (where n is the number of fields you have declared) before calling the PutRecord function, and this is where the results of a GetRecord call are stored.
FieldLength(n) should be used and modified only by the functions. You should not modify its values yourself. If you need, you can find some additional information from it: FieldLength(0) stores the number of total fields in one record, FieldLength(n+1) stores the size of one record in bytes/characters (it can be accessed like that size = FieldLength(FieldLength(0)+1) but there should be no practical need to do so.
Before using any of the functions OpenRandomFile should be called first. Only one file can be open at a time (since arrays are global).
Before the program ends or before opening another file CloseRandomFile must be called.
In a GUI database program, it is OK to open the database file at the beginning of the program, and not close it until in the trapclose branch.
Although most of these functions perform some sort of error checking (to prevent attempts to write or read beyond end of file) and return 0 if this should happen, you should not rely on this feature. As a good programmer it is your task to make sure that all those functions return 1 (success, no eof error).
Of course, no error checking can prevent misuse of the functions and coding errors.
All these functions may be used without restrictions. You may modify them to suit your needs, or use them as they are.
A source file containing the whole collection and examples of its usage, can be downloaded at Just Basic Files Archive
Main functions:
function OpenRandomFile(fileName$, fieldLengths$)
This function opens file called fileName$ for random access file I/O. The second argument is a string containing the length of each field separated by a space. The function returns the total number of records in the file.
So OpenRandomFile("mydata.dat", "16 8 2") opens "mydata.dat" and sets up 3 fields: 16 characters, 8 characters and 2 characters respectively. You can now use RecordField$(1)...RecordField$(3).
function OpenRandomFile(fileName$, fieldLengths$)
while word$(fieldLengths$, fieldCount+1) <> ""
fieldCount = fieldCount+1
wend
redim RecordField$(fieldCount)
redim FieldLength(fieldCount+1)
FieldLength(0) = fieldCount
for i = 1 to fieldCount
FieldLength(i) = val(word$(fieldLengths$, i))
size = size+FieldLength(i)
next i
FieldLength(fieldCount+1) = size
open fileName$ for binary as #randomarray
OpenRandomFile = lof(#randomarray)/size
end function
sub CloseRandomFile:
This sub closes the file opened with OpenRandomFile. Remember to call it before the program ends.
sub CloseRandomFile
close #randomarray
end sub
function PutRecord(no):
This function saves the current contents of RecordField$( in the file as record number no. The function returns 1 if successful, or 0 if it failed because no would have been beyond end of file.
function PutRecord(no)
for i = 1 to FieldLength(0)
s$ = s$+left$(RecordField$(i)+space$(FieldLength(i)), FieldLength(i))
next i
pos = (no-1)*FieldLength(FieldLength(0)+1)
if pos >= 0 and pos <= lof(#randomarray) then
PutRecord = 1
seek #randomarray, pos
print #randomarray, s$
end if
end function
function GetRecord(no):
This function reads record number no from the file and writes it to array RecordField$(. The fields are automatically trimmed of all padding whitespace. The function returns 1 if successful, or 0 if no was beyond end of file.
function GetRecord(no)
pos = (no-1)*FieldLength(FieldLength(0)+1)
if pos >= 0 and pos+FieldLength(FieldLength(0)+1) <= lof(#randomarray) then
GetRecord = 1
for i = 1 to FieldLength(0)
seek #randomarray, pos
RecordField$(i) = input$(#randomarray, FieldLength(i))
RecordField$(i) = trim$(RecordField$(i))
pos = pos+FieldLength(i)
next i
end if
end function
Additional functions:
In addition to the above main functions, there are several additional functions available. These functions are designed to facilitate some common tasks with database file I/O.
function FindRecord(key$, fieldNo, startFrom, mode$):
This function returns the number of the first record where key was found, or 0 if there were no matches.
The parameters are:
key$ - string to look for
fieldNo - number of the field to search in. (This number, of course, must not be larger than the total number of fields in a record.)
startFrom - number of the first record to start search with.
If you want to search from the beginning of the file, this value must be 1.
If, for example, you have found one match and want to continue with the rest of the file, this value should be (match+1).
mode$ - string specifying the search mode. Modes are:
"matchcase" or "" - find exact match, case sensitive search
"nomatchcase" - find exact match, not case sensitive search
"partial" or "partial matchcase" - find partial match (key$ is a substring of a field), case sensitive
"partial nomatchcase" - same as previous, except not case sensitive
E.g, n = FindRecord("John", 2, 14, "") searches for an exact match to "John" in field #2, starting from record #14.
Note: this function calls the GetRecord function, which must be included.
function FindRecord(key$, fieldNo, startFrom, mode$)
RecordCount = lof(#randomarray)/FieldLength(FieldLength(0)+1)
select case lower$(mode$)
case "nomatchcase"
for i = startFrom to RecordCount
a = GetRecord(i)
if lower$(RecordField$(fieldNo)) = lower$(key$) then
FindRecord = i
exit for
end if
next i
case "partial nomatchcase"
for i = startFrom to RecordCount
a = GetRecord(i)
if instr(lower$(RecordField$(fieldNo)), lower$(key$)) > 0 then
FindRecord = i
exit for
end if
next i
case "partial matchcase", "partial"
for i = startFrom to RecordCount
a = GetRecord(i)
if instr(RecordField$(fieldNo), key$) > 0 then
FindRecord = i
exit for
end if
next i
case else ' = "matchcase"
for i = startFrom to RecordCount
a = GetRecord(i)
if RecordField$(fieldNo) = key$ then FindRecord = i : exit for
next i
end select
end function
function GetField$(recordNo, fieldNo):
This function returns a string with a single field from record number recordNo. Unlike other functions it does not perform error checking.
function GetField$(recordNo, fieldNo)
i = 1
while i < fieldNo
size = size+FieldLength(i)
i = i+1
wend
pos = (recordNo-1)*FieldLength(FieldLength(0)+1)+size
seek #randomarray, pos
GetField$ = input$(#randomarray, FieldLength(fieldNo))
GetField$ = trim$(GetField$)
end function
function PutField(putWhat$, recordNo, fieldNo):
This function is for saving (modifying) the contents of one field only. Field number fieldNo of record recordNo is overwritten with the contents of putWhat$. The string is is padded or truncated as needed. The function returns 1 for success or 0 for failure.
function PutField(putWhat$, recordNo, fieldNo)
i = 1
while i < fieldNo
size = size+FieldLength(i)
i = i+1
wend
pos = (recordNo-1)*FieldLength(FieldLength(0)+1)+size
if pos >= 0 and pos <= lof(#randomarray) then
PutField = 1
putWhat$ = left$(putWhat$+space$(FieldLength(fieldNo)), FieldLength(fieldNo))
seek #randomarray, pos
print #randomarray, putWhat$
end if
end function
function EraseRecord(no):
This function overwrites record number no with spaces, thus erasing it's contents, and returns 1 for success or 0 for failure.
Note: it does not remove the record from the disk, therefore a call to this function does not reduce the total number of records in the file.
function EraseRecord(no)
pos = (no-1)*FieldLength(FieldLength(0)+1)
if pos >= 0 and pos <= lof(#randomarray) then
EraseRecord = 1
seek #randomarray, pos
print #randomarray, space$(FieldLength(FieldLength(0)+1))
end if
end function
function FindEmptyRecord():
This function returns the number of the first empty record in the file, or 0 if there are no empty records.
Note: if the database application provides means to delete records, then over time the file may contain several empty records. To conserve disk space in this case it would be recommended to add a new record to the end of the file only if there are no empty records in the file, otherwise those unused spaces could be overwritten instead.
function FindEmptyRecord()
size = FieldLength(FieldLength(0)+1)
RecordCount = lof(#randomarray)/size
for i = 1 to RecordCount
seek #randomarray, pos
s$ = input$(#randomarray, size)
if trim$(s$) = "" then
FindEmptyRecord = i
exit for
end if
pos = pos+size
next i
end function
function FieldsFit():
This function can be used before saving a record to check if any of the fields would be truncated, in which case users could be warned about data loss. The function returns 0 if no fields would be truncated, or the number of the first field that doesn't fit into the file and needs to be truncated.
function FieldsFit()
for i = 1 to FieldLength(0)
if len(RecordField$(i)) > FieldLength(i) then
FieldsFit = i
exit for
end if
next i
end function