Голосование

Какой почтовый клиент Вы используете?

Microsoft Outlook
Outlook Express
The Bat!
Thunderbird
Eudora
Opera
Веб-интерфейс
Другой



Посмотреть результаты
Другие опросы ...

 

Лента RSS, новости сайта Новости сайта
Лента RSS, новости форума Новости форума
  Bookmark and Share

Архив исходников

   
  Базы данных
  Графика & Мультимедиа
  Сети & Интернет
  Система
  Разное
   

Кнопки, Ссылки и Баннеры ...

 


Automatic translation


English German French Italian Spanish
Portuguese Greece Japan Chinese Korean


Ссылки и Баннеры


скрыть

 

Delphi Sources

Delphi Sources

 

 

СТАТЬИ

 

. : База данных на типизированных бинарных файлах : .

 

     Когда программист, при разработке программного продукта, сталкивается с необходимостью сохранения данных, то перед ним неизбежно возникает вопрос о выборе типа БД: локальная или многопользовательская, таблицы или СУБД. И, какой бы выбор он ни сделал, у них у всех есть одно безусловное преимущество: удобство выборки и сортировки данных. Но есть определённые и недостатки.

     Место на диске
     Как известно, база данных очень быстро растёт. И не только за счёт новых записей, но и за счёт фактического не удаления старых. Записи в таблицах и СУБД всего лишь помечаются пометкой на удаление, но физически не удаляются.

     Дополнительные инструменты
     Часть таблиц и СУБД не будут работать без установки дополнительных компонентов: сервера (программы) или драйверов.

     Время выполнения поиска и выборки данных
     Программа общается с БД через специальные инструменты, которые занимаются проверкой данных, да и поиск в БД занимает определённое время.

     Ёмкость кода
     Язык SQL универсальный и очень гибкий, но так же и очень ёмкий.

     Конечно, когда речь идёт о серьёзных программах, то все эти недостатки воспринимаются как само собой разумеющееся. Но если нам нужна база данных, в которой нужно просто фиксировать и изменять данные без последующей обработки и вывода результата в таблице, то я предлагаю воспользоваться бинарными файлами. База данных на типизированных бинарных файлах хоть и лишена прелестей БД на таблицах и СУБД, но и лишена их недостатков. Как известно, файлы занимают равно столько места на диске, сколько и текст, который они хранят. При удалении файла информация удаляется сразу и навсегда. Никаких дополнительных инструментов для работы с такой БД нам не нужно, всё есть в Delphi. Так как мы сами сообщаем программе имя файла с нужной информацией, то программе не нужно его искать по всему жёсткому диску. Код программы минимальный, по сравнению с SQL.

     Для пробы напишем простенькую программу для библиотеки. С помощью неё мы создадим электронный каталог для абонентов и книг. Создайте новый проект. Название формы MainForm. Закиньте туда два групбокса (GroupBox). Расположите их на правой и левой части формы. Левый подпишите "Абоненты", а правый "Книги" (свойство Caption). Закиньте на групбокс "Абоненты" 6 лейблов (Label), 5 эдитов (Edit), 1 мемо (Memo) и 5 кнопок SpeedButton из вкладки Additional. На групбокс "Книги" положите 7 лейблов (Label), 7 эдитов (Edit), и 5 кнопок SpeedButton. Расставьте и подпишите все элементы следующим образом:
 

Главное окно программы

Рис. 1 – Главное окно программы


     Теперь создадим две структуры (record) Abonent и Kniga. Вот они:
 


     В данном случае структуры как нельзя лучше подходят для нашей цели. С одной стороны структуры позволяют собрать под одним именем целый список переменных характеризующую одну запись, которую можно сравнить с одной строкой в таблице. С другой стороны нет необходимости записывать в файл каждую переменную структуры по отдельности, мы будем записывать в файл саму структуру целиком. В каждой структуре мы будем хранить данные, относящиеся к абоненту (TAbonent) и к книге (TKniga). У каждого абонента есть фамилия (Fio), адрес (Adres) и телефон (Telefon). Параметр Data это дата выдачи книг в библиотеке, Spisok – это список книг, которые абонент взял из библиотеки. Каждую книгу можно охарактеризовать названием (Name), автором (Avtor), жанром (Janr) и инвентарным номером (Nomer). Все книги в библиотеке разложены по разделам (Razdel), и их постоянно берут абоненты (Abonent). Теперь создадим по экземпляру от каждой структуры, а также переменные типизированных бинарных файлов:
 


     Мы их создали в разделе Public, так как наша программа будет иметь несколько форм и важно, что бы в каждой форме они были видны. Переменные типизированных файлов нужны для хранения дескриптора файла, отдельно для файлов записей абонентов и книг. В каталоге, где находится наша программа, мы создадим две папки: "Абоненты" и "Книги". В них и будет храниться вся наша база данных. Теперь напишем код для записи данных об абоненте в нашу базу данных. Щёлкнем два раза на кнопку "Запись" в разделе "Абоненты". В функции нажатии кнопки напишем такой вот код:
 


     В первой строке кода мы указываем в качестве текущего каталога папку "Абоненты":

     SetCurrentDir(ExtractFilePath(Application.ExeName) + 'Абоненты');

     Теперь ссылки на работу с файлами будет подразумеваться, что искомый файл находиться именно в этой папке и нигде больше. Далее идёт код заполнения экземпляра структуры данными:

     Abonent.Fio := Edit2.Text;
     Abonent.Adres := Edit3.Text;
     Abonent.Telefon := Edit4.Text;
     Abonent.Data := Edit5.Text;
     Abonent.Spisok := Memo1.Text;

     Далее мы ассоциируем переменную типизированного файла с конкретным файлом, иначе говоря, получаем дескриптор (ссылку) на конкретный файл, куда мы будем записывать данные:

AssignFile(DAbonent, Edit2.Text);

     При этом заметьте, что название файла соответствует имени абонента.
Далее мы открываем файл в режиме записи, если такого файла нет, то мы его создаём:

     ReWrite(DAbonent);

     Если такой файл уже существует, то вся информация на нём будет удалена. Как вы понимаете, изменение информации в файле равносильно созданию нового файла.
Далее мы записываем в файл экземпляр нашей структуры с данными об абоненте:

     Write(DAbonent, Abonent );

     После чего закрываем файл:

     CloseFile(DAbonent);

     Затем проверяем наличие созданного файла:

     if FileExists(Edit2.Text) = True
     then ShowMessage('Запись сохранена');

     Скомпилируйте проект. В поле "ФИО" напишите: Петров Дмитрий Николаевич, в поле "Адрес": советская дом 6, поле "Телефон": 555-555-555, "Дата выдачи книг": 17 февраля 2011, "Список": Последний из Могикан, Остров сокровищ, Дело о хромой канарейки. Нажмите кнопку "Запись" и все данные сохраняться в новый файл "Петров Дмитрий Николаевич", который создаться в папке "Абоненты", о чём программа выдаст соответствующее сообщение. Теперь мы можем создавать новые записи об абонентах и редактировать старые. Но, что бы редактировать старые, не плохо было бы их найти и просмотреть. Щёлкаем два раза на кнопке "Найти", в разделе "Абонент", и пишем такой код:
 

     Собственно, это нельзя назвать поиском. Мы просто проверяем наличие файла:

     if FileExists(Edit1.Text) = True

     если он есть, то получаем его дескриптор:

     AssignFile(DAbonent, Edit1.Text);

     Открываем в режиме чтения:

     Read(DAbonent, Abonent);

     Считываем с него структуру с данными:

     Read(DAbonent, Abonent);

     И закрываем его:

     CloseFile(DAbonent);

     Затем загружаем данные со структуры в соответствующие поля:

     Edit2.Text := Abonent.Fio;
     Edit3.Text := Abonent.Adres;
     Edit4.Text := Abonent.Telefon;
     Edit5.Text := Abonent.Data;
     Memo1.Text := Abonent.Spisok;

     А если нужного файла не окажется, то выдаём сообщение пользователю:

     ShowMessage('Файл не найден');

     А если вдруг нам попадётся файл, который не будет содержать структуру, или будет содержать не правильную структуру, а такого исключать ни в коем случае нельзя, то, что бы программа не выдала ошибку, мы ставим ловушку:

     try
          ...
          ...
          ...
     except
          Exit;
     end;


     Скомпилируйте проект, в поле "Поиск" напишите: Петров Дмитрий Николаевич, затем нажмите кнопку "Найти". В полях: "ФИО", "Адрес", "Телефон", "Дата выдачи книг" и "Список" появится сохранённая информация. В нынешнем варианте программы есть только один недостаток – она не позволяет видеть список всех абонентов. Так исправим его. Создадим новую форму и назовём её SpisokAbonentForm. Свяжем новую форму с главной формой:

     implementation

     uses Main;

     {$R *.dfm}

     На форму SpisokAbonentForm кинем экземпляр компонента ListView из вкладки Win32. Но перед дальнейшим использование надо предварительно его настроить:

     ViewStile := vsReport
     SortTipe := stText
     GridLines := True
     FlatScrollBars := True

     В свойстве Columns нажмите троеточие:
 

Инспектор объектов

Рис. 2 – Инспектор объектов


В появившемся окне нажмите ADD NIW. В списке появиться новое поле ListView`а, отметьте его, в свойстве Caption напишите "ФИО", а в свойствах MaxWidth, MinWidth и Width напишите "300".
 

Свойства ListView

Рис. 3 – Свойства ListView

 

Свойства ListView

Рис. 4 – Свойства ListView


     Закройте список полей ListView. В функции активации формы SpisokAbonentForm напишем такой код:
 


     С помощью этого кода при открытии формы SpisokAbonentForm в ListView будет загружаться список всех абонентов. Суть формирования списка всех абонентов заключается в поочерёдном чтении названий файлов из папки "Абоненты" и загрузка их в ListView. Для начала мы создаём экземпляр структуры TSearchRec:

     var
          SearchAbonent : TSearchRec;

     В нём будут храниться все данные о найденном файле, в том числе его имя.
Затем всё удаляем из списка ListView`а:

     ListView1.Items.Clear;

     Устанавливаем в качестве текущего каталога папку "Абоненты". Затем мы поочерёдно проверяем все файлы каталога Абоненты:

     if FindFirst('*', faReadOnly, SearchAbonent) = 0 then begin
     repeat

     прошу обратить внимание на первый и второй атрибуты функции FindFirst:

     '*' – означает, что будут искаться все файлы с любым названием и любым расширением.
     faReadOnly – означает, что в поиске будут участвовать только файлы для чтения. Если данный атрибут заменить на faAnyFil, то в поиске будут участвовать не только все файлы, но и каталоги, включая каталог верхнего уровня, что нам совсем не нужно.

     Далее название найденного файла мы добавляем в список ListView`а:

     ListView1.Items.Add.Caption := SearchAbonent.Name;

     Проверяем, есть ли ещё файлы в данном каталоге:

     until FindNext(SearchAbonent) <> 0;

     И, если таковых нет, прекращаем поиск:

     FindClose(SearchAbonent);
     end;

     Теперь в функции кнопки "Список абонентов" на главной форме пишем код загрузки окна
SpisokAbonentForm:

     procedure TMainForm.SpeedButton7Click(Sender: TObject);
     begin
          SpisokAbonentForm.ShowModal;
     end;

     Список всех абонентов мы построили, причём в алфавитном порядке (SortTipe := stText), но было бы не плохо, что бы библиотекарь мог одним двойным кликом на строку с именем абонента загрузить данные по абоненту в программу. Для этого в функцию onDblClick нашего ListView`а в форме SpisokAbonentForm запишем следующий код:
 


     Код нам известен на столько, что нет смысла его разбирать. Единственное на что нужно обратить внимание, так это на параметр ListView1.Selected.Caption. Здесь храниться выбранная из списка ListView'а запись.

     Теперь заполним кодом кнопку "Очистить". Она будет удалять записи со всех полей, кроме поиска:
 


     Здесь, в общем, тоже комментировать нечего.
     Ну, и для полного счастья осталось только создать функцию удаления записи. Для этого создаём ещё одну форму DelAbonentForm. Кидаём на неё лейбл и две кнопки. Должно получиться вот так:

 

Удаление обонента

Рис. 5 – Удаление обонента


     В функции нажатии кнопки "Да" формы DelAbonentForm пишем такой код:
 


     Здесь мы проверяем наличие удаляемого файла, и с помощью функции DeleteFile(NameFile) удаляем его. Обо всех возможных результатах сообщаем пользователю при помощи функции ShowMessage('текст сообщения'). Здесь надо только помнить, что прежде чем удалять файл, его надо загрузить при помощи поиска, так как имя удаляемого файла определяется в Edit2.Text.

     В функции кнопки "нет" мы просто закрываем форму:

     procedure TDelAbonentForm.SpeedButton2Click(Sender: TObject);
     begin
          Close;
     end;

     Для того, что бы активировать функцию удаления абонента, в функции кнопки "Удалить" раздела "Абоненты" на главной форме пишем код загрузки окна DelAbonentForm:

     procedure TMainForm.SpeedButton3Click(Sender: TObject);
     begin
          DelAbonentForm.ShowModal;
     end;

     Вторую часть программы, по работе с каталогом книг, я комментировать не буду, приведу только сам код. Этот код повторяет код работы с абонентами, разница заключается лишь в том, данные о книге сохраняются в экземпляре другой структуры:

     Kniga: TKniga;

     И дескриптор файла сохраняется в другой переменной:

     DKniga: file of TKniga;

     Код кнопки "Запись":
 


     Код кнопки "Найти":
 


     код кнопки "Список книг":

     procedure TMainForm.SpeedButton9Click(Sender: TObject);
     begin
          SpisokKnigForm.ShowModal;
     end;

     название формы для списка книг SpisokKnigForm.

     Скриншот формы SpisokKnigForm:
 

Список всех книг

Рис. 6 – Список всех книг


     Код активации формы SpisokKnigForm:
 


     Код двойного клика на ListView:
 


     Код кнопки "Удалить":

     procedure TMainForm.SpeedButton6Click(Sender: TObject);
     begin
          DelKnigaForm.ShowModal;
     end;

     Окно удаления книги: DelKnigaForm.
     Скриншот окна DelKnigaForm:
 

Окно удаления книги

Рис. 7 – Окно удаления книги


     Код кнопки "Да":
 


     Код кнопки "Нет":

     procedure TDelKnigaForm.SpeedButton2Click(Sender: TObject);
     begin
          Close;
     end;

     И код кнопки "очистить" в главной форме:
 


     Вот мы и создали программу, база данных которой состоит из типизированных двоичных файлов. Размер самой программы, так же как и размер каждого файла с записью невелик. Такая программа не обременит компьютер ни по ресурсам системы, ни по ёмкости жёсткого диска. Таким образом, можно создавать любые другие каталоги, например, каталог CD и DVD дисков. Сохранять можно не только текстовую информацию, но и числа и даже картинки или фотографии. Осталось добавить один маленький штрих. Посмотрите на код наших структур:
 


     Все данные типа String строго лимитированные. Для чего это нужно. Это необходимое условие для создания, типизированного файла. Если данные задаются строкой или набором символов, то их размер должен быть строго определён. Попробуйте убрать размер длины строки хотя бы у одной переменной, и компилятор выдаст ошибку. Что касается последнего штриха, то он довольно прост. Если переменные лимитированные, то и эдиты, через которые вводятся данные, тоже должны иметь лимит ввода. Это можно легко организовать при помощи свойства MaxLength эдитов и мемо.
 

Обсуждение статьи на Форуме...
Оригинал статьи: database-bin-files.zip (108 Кб).
Дата:
19.02.2011, Автор: Александр Лобутев.






Назад

 

© 2004-2017 "DS"

Отправить письмо / Реклама


ВКонтакте   Facebook   Twitter