📄 kfs.doc
字号:
30
Interdependencies of the KFS operations
Except for the requirements for opening databases first and
closing databases last, there is no specific dependencies
between KFS operations. That is, there is no requirement to call
a specific function before another function can be called. For
example, it is not necessary to read a specific record before
replacing it with KFS_Replace. The same is true if you want to
delete a record, it is not necessary to read it first. Simi-
larly, you can issue a KFS_ReadNext after any other operation,
as long as the key of an existing record is present in the data
area so that KFS_ReadNext can read the record with the next
highest key.
31
Special Processing
There are a few special options that may be chosen when creating
a database with the Keyed File System that allow for special
uses of databases. These options are enabled by setting certain
bits in the KFS_flags field of the File Information Structure.
If none of the options are desired, the flags field should be
set to KFS_Normal_PTR. Normally, databases are relatively large
databases (such as customer record databases) with keys that
contain primarily letters (people's names, for example) and the
Keyed File System was designed to handle these databases most
efficiently. Some assumptions are made about the number and type
of keys that will exist in the database when it is created and
results in creating an initial .PTR file of about 8K bytes.
Because of this initial allocation, the .PTR file is normally
slow to grow. However, for some applications, the assumptions
made by the Keyed File System may not be correct. Three options
are provided to enable the programmer to select a more efficient
initial .PTR allocation or to utilize various types of keys.
KFS_Small_PTR
For applications that need relatively small databases (up to a
few hundred records), the KFS_Small_PTR option provides a way to
greatly reduce the initial size of the .PTR file from 8K to a
few hundred bytes. However, using this option will result in
slower execution speed if the database does grow large. Note
that this does not prohibit the database from becoming large,
just that performance is slower should it do so.
The option is enabled by setting the KFS_flags field to
KFS_Small_PTR. In C this could be done by the following code :
#include <kfs.h>
KFS_FILEINFO file1;
file1.KFS_flags = KFS_Small_PTR;
KFS_Numeric_Key
For applications whose keys are all numbers, it would be more
efficient of these numbers could be stored in the normal way
that the Intel 80x86 stores numbers. That is, in byte reversed
binary form (ie. short, int, or long in C terminology). The
Keyed File System provides the KFS_Numeric_Key option that
allows the key to be stored in the 4 byte Intel integer format
(ie. C's "long int"). Using this option will cause the system to
assume that KFS_keypos indicates the beginning of a 4 byte key
that is a number stored in integer form. KFS_keylen is ignored
when this option is specified.
The option is enabled by setting the KFS_flags field to
KFS_Numeric_Key. In C this could be done by the following code :
#include <kfs.h>
KFS_FILEINFO file1;
file1.KFS_flags = KFS_Numeric_Key;
32
KFS_Ignore_Case
Normally, databases created with alphabetic keys are sensitive
to the case of the keys. That is, keys "ABCDE" and "abcde"
indicate the keys of two different records. However, setting
this option allows case to be ignored for databases that have
alphabetic keys. Then a database created with this option would
treat the keys "ABCDE" and "abcde" as the key to the same
record.
The option can be combined with the KFS_Normal_PTR or
KFS_Small_PTR options and is enabled by setting the KFS_flags
field to KFS_Ignore_Case. In C this could be done by the fol-
lowing code :
#include <kfs.h>
KFS_FILEINFO file1;
file1.KFS_flags = KFS_Normal_PTR | KFS_Ignore_Case;
33
Programming Hints and Tips
In this section we will try to provide some hints, examples,
and, hopefully, the answers to some questions to help an appli-
cation developer in using the Keyed File System. As part of the
KFS package we have included the source to the sample and util-
ity programs we have provided. These programs will provide some
concrete coding examples of how to use the functions we have
described. Use them to reinforce some of the examples we use in
this section.
* Ensure that when creating a database that the KFS_flags
field is properly set to one of the valid options.
* When specifying a key in the data area for an operation
that requires a key, make sure that all bytes in the key
field are set to a known value. Remember, the Keyed File
System always assumes the key is KFS_keylen bytes long,
irrespective of any NULLS in the key field. A common mis-
take is not to "clear" the key field before moving in a key
that may be shorter than keylen. For example, STRCPY only
moves data until a '00'X is detected in the source. Thus,
if what is being moved in is shorter than KFS_keylen, the
remaining bytes of the key field will remain unchanged (ie.
may contain garbage). Additionally, consider that STRCPY
also moves the terminating NULL character and that will
become part of the key. This may be OK, just realize that
the NULL is there. A good habit to get into when using KFS
functions is illustrated by the following code:
#include <kfs.h>
KFS_FILEINFO file1;
char area[80];
memset(&area[file1.KFS_keypos], ' ', file1.KFS_keylen);
strcpy(&area[file1.KFS_keypos, newkey);
This code sequence initially sets the key field of "area"
to blanks and then copies in the desired key from the
"newkey" variable.
* You will notice that the Keyed File System does not allow
for duplicate keys. However, with a little thought, the
KFS_ReadGen and KFS_ReadNext functions can be used to pro-
vide a similar capability. For example, if you wanted to
have a database whose key was a name field, duplicate names
could be avoided by making the key field the name AND
account number. You could still issue a KFS_ReadGen for
only the name and then use KFS_ReadNext to read the rest of
the records having the same name.
* If KFS_ReadNext tries to read the next record after the
last logical record in the database (ie. the record with
the highest key) a KFS_EOF is returned. If another
KFS_ReadNext is issued, KFS_EOF will again be returned.
However, other operations (such as KFS_Read) are still
allowed on the database and will result in KFS_rc to be set
to another value (such as KFS_OK if the read is success-
ful). Further KFS_ReadNext operations may be performed from
that spot in the database.
34
* We mentioned earlier that numeric and alphabetic keys can-
not be combined. However, if you keep in mind that shorts
and longs are stored in byte reversed format, you can form
keys that mix data types. The following code segment com-
bines an alphabetic customer name and a numeric (i.e. long)
customer number into a single key. The customers names
would be in the database in alphabetic sequence, but cus-
tomers with the same name would not necessarily be in
sequence by customer number (customer number 256, stored as
'00010000'x, would be before customer number 255, stored as
'FF000000'x, for example).
#include <kfs.h>
struct DA {
char custname[40];
long custnum;
char morestuff[40];
} myarea;
KFS_FILEINFO myfile;
:
myfile.KFS_keypos = 0;
myfile.KFS_keylen = 44;
:
KFS_Create(&myfile);
35
Data Recovery
Most programmers are familiar with damaged data files caused by
unusual system problems (power failures or system crashes) while
a file is being written to disk. While these problems are rare,
they do occur. The Keyed File System contains code that attempts
to minimize the impact of such a system failure, but this impact
cannot be eliminated completely. Since the Keyed File System
uses two related DOS files (an index file and a data file) to
manage a database, damage to one of these files can cause the
database to become unusable. With a little planning, however, a
programmer can frequently recover a damaged KFS database with
little or no loss of data. To do this requires a little knowl-
edge of the internals of KFS.
The data file that makes up a KFS database is a normal DOS
binary file. That is, each "logical" record is KFS_recsize bytes
long and does not contain a CR/LF at the end of each record.
Thus, these records can be read using operating system or C
language functions just like any other binary file. Addition-
ally, when KFS deletes a record, it is not physically removed
from the data file but only from the .PTR file. However, it is
marked for reuse and a hex 'FF' is placed in the last byte of
the data record when a record is deleted. This hex 'FF' has no
consequence to KFS since deleted records are tracked another way
internally, but can be useful for a programmer wanting to
recover a damaged KFS database by using only the data file. If,
when writing an application, a programmer using the Keyed File
System ensures that the last byte of each data record cannot
normally be hex 'FF', then recovering a KFS database can be
relatively simple. A database recovery program can be written
that simply reads the data portion of the damaged KFS database
as fixed length binary records, checks to ensure the last byte
of each record is not hex 'FF' (remember, hex 'FF' means the
record has been deleted), and uses the KFS_Add operation to add
the record to a new KFS database. At the conclusion of such a
recovery program, the new KFS database would contain all of the
undamaged records that existed in the original KFS database. A
simple example of this technique appears in Appendix B.
36
Appendix A - Keyed File System Return Codes
The following is a list of return codes generated by the Keyed
File System. These definitions are found in the supplied header
file (KFS.H).
KFS_OK (0)
The operation completed successfully.
KFS_Data_File_Open_Error (3)
A bad return code was return from the system when trying to
open the data file of the database.
KFS_EOF (-1)
End of file was reached on the data database during a
KF
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -