Довольно часто случается, что в программе необходима маленькая база данных (записей на 50-200, не более). Так что же? Брать mdb-шный файл (что само по себе "кусаемо" по объемам) плюс привязывать к нему для работы библиотеки ADO (или DAO). Не слишком ли "жирно" для 50 записей?
В данной статье я хочу показать вариант сохранения базы данных в текстовом файле. Попутно будет рассмотрено еще несколько вопросов. Итак:
· сохранение БД в файле формата txt, используя объектно-ориентированный подход к программированию;
· работа с диалоговыми окнами открытия и сохранения файлов через API-функции и построение собственного класса для этого;
· работа с VB 6 Class Builder Utility;
· считывание и запись информации в файлы последовательного доступа, используя библиотеку FSO (FileSystemObject).
Я проведу Вас пошагово от начала до конца. В результате получим упрощенный вариант телефонного справочника.
Шаг 1. Откройте новый проект и создайте форму, аналогичную, нарисованной ниже.
Текстовые поля называются txtLastName, txtFirstName, txtNumber. Первая колонка кнопок носит названия cmdDB, с индексами соответственно от 0 до 2; вторая колонка – cmdEdit (Index = 0 to 2); и наконец кнопки внизу, заведующие перемещением по записям – cmdMove (Index = 0 to 3). Лейбл-индикатор номера записи носит имя lblID.
Шаг 2. Для поиска файла можно использовать стандартный элемент управления CommonDialog. При желании, можно построить диалоговую форму самому (с помощью стандартных встроенных ЭУ: Dir, Drive, File). И, наконец, можно использовать API-функции, напрямую обращаясь к библиотекам Windows. Рассмотрим последнюю возможность, но сделаем специальный класс для работы с диалоговым окном. Впоследствии Вы сможете многократно использовать этот класс в различных своих программах.
Здесь нам поможет утилита для создания классов. Выберите меню Add-Ins/Add-In Manager… и в диалоговом окне отметьте опцию VB 6 Class Builder Utility. Нажмите ОК. А теперь выберите непосредственно это меню Add-Ins/Class Builder Utility… Создадим новый класс и назовем его clsCommonDialog. Для этого выберите меню File/New/Class… Замените предлагаемое по-умолчанию имя Class1 на выбранное нами и подтвердите нажатием на кнопку "ОК". Теперь создадим свойства для этого класса (меню File/New/Property…). Все они перечислены ниже в таблице:
Name | Type |
Action |
Integer |
APIReturn |
Long |
CancelError |
Boolean |
DefaultExt |
String |
DialogTitle |
String |
ExtendedError |
Long |
FileName |
String |
FileTitle |
String |
Filter |
String |
FilterIndex |
Integer |
Flags |
Long |
hdc |
Long |
InitDir |
String |
MaxFileSize |
Long |
И два метода (меню File/New/Method…): ShowOpen и ShowSave. Оба метода без аргументов.
Закроем утилиту, подтвердив произведенные изменения. И перейдем в только что созданный класс.
Для работы нам понадобится три API-функции и один Type:
Private m_cancelled As Boolean
'****************************************************
'API
function
'****************************************************
'API функция для ShowOpen method
Private
Declare Function GetOpenFileName Lib "comdlg32.dll" _
Alias
"GetOpenFileNameA" (pOpenfilename As OpenFilename) As Long
'API функция для ShowSave method
Private
Declare Function GetSaveFileName Lib "comdlg32.dll" _
Alias
"GetSaveFileNameA" (pOpenfilename As OpenFilename) As Long
'API функция для возвращения расширенной информации об ошибке
Private Declare Function CommDlgExtendedError Lib "comdlg32.dll" () As Long
'****************************************************
'Type
'****************************************************
Private
Type OpenFilename
lStructSize As Long
hwndOwner As Long
hInstance As Long
lpstrFilter As String
lpstrCustomFilter As String
nMaxCustFilter As Long
iFilterIndex As Long
lpstrFile As String
nMaxFile As Long
lpstrFileTitle As String
nMaxFileTitle As Long
lpstrInitialDir As String
lpstrTitle As String
Flags As Long
nFileOffset As Integer
nFileExtension As Integer
lpstrDefExt As String
lCustData As Long
lpfnHook As Long
lpTemplateName As String
End
Type
Для свойств Action, APIReturn и ExtendedError удалим блоки с Property Let – эти свойства только для чтения.
Теперь займемся методами. И тот и другой метод у нас опираются на одну и ту же процедуру ShowFileDialog, только с разными индексами:
Public Sub ShowOpen()
'вывод на экран диалога "Открыть файл"
ShowFileDialog (1)
End Sub
Public Sub ShowSave()
' вывод на экран диалога "Сохранить файл"
ShowFileDialog (2)
End Sub
Вся суть этого класса как раз и заключается в процедуре ShowFileDialog. В ней происходит передача значений из свойств в объект tOpenFile, для последующего использования в API-функциях.
Private Sub ShowFileDialog(ByVal iAction As Integer)
Dim tOpenFile As OpenFilename
Dim lMaxSize As Long
Dim sFileNameBuff As String
Dim sFileTitleBuff As String
On Error GoTo ShowFileDialogError
'инициализация буфера
iAction = iAction 'Action property
lApiReturn = 0 'APIReturn property
lExtendedError = 0 'ExtendedError property
tOpenFile.lStructSize = Len(tOpenFile)
tOpenFile.hwndOwner = lhdc
'Замена "|" на Chr(0)
tOpenFile.lpstrFilter = sAPIFilter(sFilter)
tOpenFile.iFilterIndex = iFilterIndex
'определение размера буфера от свойства MaxFileSize
If lMaxFileSize > 0 Then
lMaxSize = lMaxFileSize
Else
lMaxSize = 255
End If
sFileNameBuff = sFileName
'заполнение пробелами до 255
While Len(sFileNameBuff) < lMaxSize - 1
sFileNameBuff = sFileNameBuff & " "
Wend
'обрежем до длины lMaxFileSize - 1
If lMaxFileSize = 0 Then
sFileNameBuff = Mid$(sFileNameBuff, 1, lMaxSize - 1)
Else
sFileNameBuff = Mid$(sFileNameBuff, 1, lMaxFileSize - 1)
End If
'установим в конце нулевой знак
sFileNameBuff = sFileNameBuff & Chr$(0)
tOpenFile.lpstrFile = sFileNameBuff
If lMaxFileSize <> 255 Then
tOpenFile.nMaxFile = 255
End If
'операции, аналогичные вышеисполненным
sFileTitleBuff = sFileTitle
While Len(sFileTitleBuff) < lMaxSize - 1
sFileTitleBuff = sFileTitleBuff & " "
Wend
If lMaxFileSize = 0 Then
sFileTitleBuff = Mid$(sFileTitleBuff, 1, lMaxSize - 1)
Else
sFileTitleBuff = Mid$(sFileTitleBuff, 1, lMaxFileSize - 1)
End If
sFileTitleBuff = sFileTitleBuff & Chr$(0)
tOpenFile.lpstrFileTitle = sFileTitleBuff
tOpenFile.lpstrInitialDir = sInitDir
tOpenFile.lpstrTitle = sDialogTitle
tOpenFile.Flags = lFlags
tOpenFile.lpstrDefExt = sDefaultExt
'выполним GetOpenFileName API-функцию
Select Case iAction
Case 1 'ShowOpen
lApiReturn = GetOpenFileName(tOpenFile)
Case 2 'ShowSave
lApiReturn = GetSaveFileName(tOpenFile)
Case Else
Exit Sub
End Select
m_cancelled = False
'Возвращение дескриптора от API-функции GetOpenFileName
Select Case lApiReturn
Case 0 'нажата кнопка Cancel
'генерация ошибки
m_cancelled = True
Exit Sub
Case 1 'пользователь выбрал или ввел файл
'Используем внутреннюю процедуру sLeftOfNull
'для получения пути и имени файла
sFileName = sLeftOfNull(tOpenFile.lpstrFile)
sFileTitle = sLeftOfNull(tOpenFile.lpstrFileTitle)
Case Else 'если произошла ошибка вызываем CommDlgExtendedError
lExtendedError = CommDlgExtendedError
End Select
Exit Sub
ShowFileDialogError:
Exit Sub
End Sub
И теперь еще две вспомогательные функции. Функция "разбирающая" значение фильтра и заменяющая знак"|" на Chr(0)
Private Function sAPIFilter(sIn)
Dim lChrNdx As Long
Dim sOneChr As String
Dim sOutStr As String
For lChrNdx = 1 To Len(sIn)
sOneChr = Mid$(sIn, lChrNdx, 1)
If sOneChr = "|" Then
sOutStr = sOutStr & Chr$(0)
Else
sOutStr = sOutStr & sOneChr
End If
Next
sOutStr = sOutStr & Chr$(0)
sAPIFilter = sOutStr
End Function
И функция "обрезающая" пробелы в названии пути и имени файла:
Private Function sLeftOfNull(ByVal sIn As String)
Dim lNullPos As Long
sLeftOfNull = sIn
lNullPos = InStr(sIn, Chr$(0))
If lNullPos > 0 Then
sLeftOfNull = Mid$(sIn, 1, lNullPos - 1)
End If
End Function
Класс для работы с диалоговым окном "Открытие-Сохранение файла" – готов.
Шаг 3. Создадим код для кнопки создания файла. В разделе деклараций объявим класс для работы с диалоговым окном:
Private dlgDb As New clsCommonDialog
А теперь сам код:
With dlgDb
.DialogTitle = "Создать текстовую БД"
.Filter = "Текстовые БД (*.tdb)|*.tdb"
.FilterIndex = 1
.ShowOpen
End With
Шаг 4. Итак, мы ввели название для файла, нажали "OK" – теперь необходимо физически создать файл с этими параметрами. С первой версии VB существуют встроенные функции открытия и сохранения файлов:
Open pathname For [Input| Output| Append] As filenumber [Len = buffersize]
Open pathname For [Random] As filenumber Len = buffersize
Open pathname For Binary As filenumber
В VB 6.0 появилась новая возможность для этого, а именно модель объекта файловой системы – File System Object (FSO), о которой мало кто знает. Для того, чтобы использовать эту библиотеку выберите меню Project/References… В открывшемся диалоговом окне выберите "Microsoft Scripting Runtime"
Лирическое отступление 1. На данный момент библиотека может работать (редактировать) только с файлами последовательного доступа. Будем надеяться, что в VB 7 появится возможность работать так же и с бинарными файлами и с файлами произвольного доступа.
В разделе деклараций объявим переменные для работы с этой библиотекой:
Private fso As New FileSystemObject ' "верхний" объект библиотеки FSO
Private tsOpen As TextStream '
Private tsSave As TextStream 'текстовые потоки библиотеки FSO
Private tsNew As TextStream '
Лирическое отступление 2. Кроме раннего связвывания FSO можно также создать и поздним связыванием, например:
Set fso = CreateObject("Scripting.FileSystemObject")
Преимуществом позднего связывания является то, что данный синтаксис будет работать не только в Visual Basic, но и в VBScript.
Лирическое отступление 3. Кроме выбранных нами FileSystemObject (главного объекта группы, управляющего дисками, папками и файлами) и TextStream (текстовый поток – позволяющий создавать, читать и записывать текстовые файлы последовательного доступа), модель FSO содержит еще три основных объекта. Это Drive (собирает информацию о дисках, присоединенных к системе), Folder (создает, удаляет и перемещает папки) и Files (создает, удаляет и перемещает файлы)
Добавляем в код строки создания файла, а затем его закрываем, изменяем заголовок формы и приравниваем переменные-счетчики (их объявление так же необходимо вынести в раздел деклараций) к нулю.
Private CountEntries As Integer' общее количество записей
Private CurrentEntries As Integer' номер текущей записи
With dlgDb
.DialogTitle = "Создать текстовую БД"
.Filter = "Текстовые БД (*.tdb)|*.tdb"
.FilterIndex = 1
.ShowOpen
'создание текстового файла последовательного доступа
Set tsNew = fso.CreateTextFile(.FileName, True)
'закрытие файла
tsNew.Close
'изменение заголовка
Caption = "Demo FSO as DB (" & .FileTitle & ")"
End With
'установка счетчиков
CountEntries = 0
CurrentEntries = 0