Такое громкое название, как "База данных" зачастую скрывает в себе лишь один или несколько файлов, в которых хранятся в определенном формате данные. Каждый способен придумать свой формат файла базы данных, но в компьютерном мире уже существуют общепринятые форматы баз данных, которые понимают многие СУБД и программы. Одним из таких форматов является 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, хранящего список полей записи.