Такое громкое название, как "База данных" зачастую скрывает в себе лишь один или несколько файлов, в которых хранятся в определенном формате данные. Каждый способен придумать свой формат файла базы данных, но в компьютерном мире уже существуют общепринятые форматы баз данных, которые понимают многие СУБД и программы. Одним из таких форматов является DBF (Data Base File). Наша задача проста: разобраться с форматом файлов DBF и написать соответствующую библиотеку классов для работы с ними. Я конечно понимаю, что это уже старо как мир и существует много готовых библиотек, но давайте напишем что-то сами для развития мозгов и своего навыка программирования.
Первым делом надо разобраться с форматом файлов DBF. На данном этапе я считаю важным разобраться только с форматом записи файла, а если быть точным, то с форматом описания структуры этой записи.
Вкратце и упрощенно о формате файла DBF. Сначала идет заголовок файла, с ним мы познакомимся чуть позже. Далее идет список полей в записи файла, т.е. имя, тип, длина соответствующего поля в записи. После этого списка идут подряд все записи файла, которые организуются по структуре описанной в списке полей.
Для полного описания поля записи используется структура длинной 32 байта, в которой:
Давайте для хранения этой структуры создадим класс DBFRecordTypeField:
class DBFRecordType;//класс для структуры записи
class DBFRecordTypeField {
friend DBFRecordType;
DBFRecordTypeField *Next, *Pred;//Переменные для списка
public:
char Name[11]; //имя поля
char Type; //тип поля
long Position; //Позиция поля в записи
unsigned char TotalLen;//Длина поля
unsigned char DecimalLen;//Длина дробной части
DBFRecordTypeField(char *name_,char type_,
unsigned char len_, unsigned char declen_);
~DBFRecordTypeField();
};
Этот класс может в себе практически ничего не содержать кроме конструктора и деструктора:
DBFRecordTypeField::DBFRecordTypeField(char *name_,
char type_, unsigned char len_, unsigned char declen_)
{
int i=0;
char b=0;
for (i=0;i<11;i++){
if ((*(name_+i)!=0)&&(b==0))
Name[i]=*(name_+i);
else {
Name[i]=0;
b=1;
};
};
Type=type_;
TotalLen=len_;
if ((Type=='F')||(Type=='N')){
DecimalLen=declen_;
} else {
DecimalLen=0;
};
if (Type=='L') TotalLen=1;
Next=NULL;
Pred=NULL;
};// DBFRecordTypeField;
Имя структуры заполняется слева направо и оставшиеся непонадобившиеся символы заполняются нулями. Переменную DecimalLen заполняем только в случае если поле вещественного или числового типа. А типы полей задаются символами соответствующих следующей табличке.
| Тип поля | Значение |
|---|---|
| Числовое | N |
| Вещественное | F |
| Символьное | C |
| Логическое | L |
| Типа MEMO | M |
| Дата | D |
Теперь осталось написать деструктор, который восстанавливает связи в нашем двусвязном списке. Почему двусвязном ? А просто так, мало ли что потом понадобится :-)
DBFRecordTypeField::~DBFRecordTypeField(){
if (Pred!=NULL) Pred->Next=Next;
if (Next!=NULL) Next->Pred=Pred;
};//~DBFRecordType;
Теперь есть элементарная "базовая ячейка", с помощью которой будем строить класс списка DBFRecordType, хранящего список полей записи.