Часть 2. Работа с ini-файлами.
Как говорилось выше, ini-файлы – это наследие прошлого. Хорошо это или плохо? Однозначного ответа нет. Существует много сторонников ini-файлов, и их основным аргументом является доступность и легкость в редактировании. Что такое, по сути, ini-файл? Это текстовый файл, разбитый внутри на секции. Заголовок каждой секции заключен в квадратные скобки. Каждая секция состоит из строк, представляющих собой название параметра (ключ) и через равно (=) – его значение. Все элементарно просто и понятно для восприятия. Однако это же самое является и отрицательным моментом. Учитывая, что нынешний Windows занимает порядка 150-300 мегабайт, имеет массу встроенных программ и каждой из них необходим свой собственный ini-файл. А, кроме того, мы инсталлируем у себя, как минимум, Офис. А как максимум еще 3-4 десятка программ. Представляете в какую "выгребную яму" превратится директория, хранящая ini-файлы? Кроме того, из-за своей простоты, ini-файлы не могут предоставить иерархическую структуру вложенности, то, что так легко удается реестру. И в заключение: ini-файл – это отдельный файл, т.е. принципиально он может храниться в любом месте, а не только Windows\System. Насколько усложнится поиск необходимого файла, из-за кажущейся "простоты редактирования".
Однако, несмотря на все минусы ini-файлы продолжают жить. Не так вольготно, как в Windows 3x, но все же. По-прежнему сохраняются 2 основных файла, несущих информацию о самом Windows (win.ini, system.ini). Поэтому давайте разберемся, как все-таки с ними надо работать.
Встроенных VB-функций для работы с ini-файлами нет, однако существуют API-функции. Излагаемый ниже материал полностью приведен в Листинге. Его можно просто скопировать и оформить как отдельный модуль или класс, который подключается по мере надобности.
Private Declare Function GetPrivateProfileInt Lib "kernel32" _
Alias "GetPrivateProfileIntA"
_
(ByVal strSection As String, _
ByVal strKeyName As
String, _
ByVal lngDefault As
Long, _
ByVal strFileName As
String) _
As Long
Private Declare Function GetPrivateProfileString Lib "kernel32"
_
Alias "GetPrivateProfileStringA"
_
(ByVal strSection As String, _
ByVal strKeyName As
String, _
ByVal strDefault As
String, _
ByVal strReturned As
String, _
ByVal lngSize As Long,
_
ByVal strFileName As
String) _
As Long
Private Declare Function WritePrivateProfileString Lib
"kernel32" _
Alias "WritePrivateProfileStringA"
_
(ByVal strSection As String, _
ByVal strKeyNam As
String, _
ByVal strValue As
String, _
ByVal strFileName As
String) _
As Long
Приведенные здесь три основные функции служат для работы с ini-файлами 2 на запись (для строкового и целочисленного параметров) и одна на чтение.
Кроме того, существует еще три API-функции (по тому же принципу), но работающие ТОЛЬКО с одним файлом WIN.INI
Private Declare Function GetProfileInt Lib "kernel32" _
Alias "GetProfileIntA" _
(ByVal strSection As String, _
ByVal strKeyName As
String, _
ByVal lngDefault As
Long) _
As Integer
Private Declare Function GetProfileString Lib "kernel32" _
Alias "GetProfileStringA"
_
(ByVal strSection As String, _
ByVal strKeyName As
String, _
ByVal strDefault As
String, _
ByVal strReturned As
String, _
ByVal intSize As Long)
_
As Long
Private Declare Function WriteProfileString Lib "kernel32" _
Alias "WriteProfileStringA"
_
(ByVal strSection As String, _
ByVal strKeyName As
String, _
ByVal strValue As
String) _
As Integer
Нетрудно заметить, что последние три функции, практически полностью повторяют первые, за исключением одного параметра – путь файла. Однако, благодаря этому, скорость их работы значительно выше.
Внутренняя структура представленных API-функций достаточно проста, и, в принципе их можно использовать "напрямую" в своих приложениях. Однако я рекомендую все же сделать функции-"обертки", так как API-функции не поддерживают обработку ошибок, и лучше это сделать самому, не дожидаясь, когда Ваша программа "скоропостижно" закончит работу.
Public Function GetValueInteger(strSection As String, _
strKey As String, strFile As
String) As Integer
Dim intValue As Integer
On Error GoTo PROC_ERR
intValue = GetPrivateProfileInt(strSection, strKey, 0, strFile)
GetValueInteger = intValue
PROC_EXIT:
Exit Function
PROC_ERR:
MsgBox "Ошибка: <" & Err.Number & "> - "
& Err.Description, _
vbExclamation +
vbOKOnly, "GetValueInteger"
Resume PROC_EXIT
End Function
Данная функция возвращает целочисленное значение из ini-файла. Где имя секции – strSection, имя ключа – strKey и strFile – полный путь к ini-файлу.
Public Function GetValueString(strSection As String, _
strKey As String, strFile As
String) As String
Dim strBuffer As String * 256
Dim intSize As Integer
On Error GoTo PROC_ERR
intSize =
GetPrivateProfileString(strSection, strKey, "", _
strBuffer, 256,
strFile)
GetValueString = Left$(strBuffer, intSize)
PROC_EXIT:
Exit Function
PROC_ERR:
MsgBox "Ошибка: <" & Err.Number & "> - "
& Err.Description, _
vbExclamation +
vbOKOnly, "GetValueString"
Resume PROC_EXIT
End Function
Данная функция возвращает строковое значение из ini-файла. Где имя секции – strSection, имя ключа – strKey и strFile – полный путь к ini-файлу. Обратите внимание, что вначале резервируется пустая строка, а из результата функции выкидываются пустоты.
Public Function SetValue(strSection As String, strKey As String, _
strValue As String, strFile As
String) As Integer
Dim intStatus As Integer
On Error GoTo PROC_ERR
intStatus =
WritePrivateProfileString(strSection, strKey, _
strValue, strFile)
SetValue = (intStatus <> 0)
PROC_EXIT:
Exit Function
PROC_ERR:
MsgBox "Ошибка: <" & Err.Number & "> - "
& Err.Description, _
vbExclamation +
vbOKOnly, "SetValue"
Resume PROC_EXIT
End Function
Данная функция записывает в файл значение strValue и возвращает целочисленное значение: True, если запись произведена и False, в случае ошибки записи. Имя секции – strSection, имя ключа – strKey и strFile – полный путь к ini-файлу.
Как уже говорилось выше, работа с файлом WIN.INI строится аналогичным образом. Поэтому повторяться здесь не буду.
До этого момента все было легко и просто. Однако встречаются ситуации, когда нам необходимо считать все значения в конкретной секции. И данные функции нам не помогут. Оказывается, существует еще одна API-функция, которая нам в этом поможет:
Private Declare Function GetPrivateProfileSection Lib
"KERNEL32" _
Alias "GetPrivateProfileSectionA"
_
(ByVal lpAppName As String, _
ByVal lpReturnedString
As String, _
ByVal nSize As Long, _
ByVal lpFileName As
String) _
As Long
Для нее так же напишем функцию-"обертку".
Public Function GetSection(strSection As String, strFile As String)
Dim strBuffer As String * 512
Dim intSize As Integer
Dim strTemp As String
Dim intTemp As Integer
Dim Index As Integer
Dim arrSection() As String
Dim key As String, value As String, str As String
On Error GoTo PROC_ERR
intSize = GetPrivateProfileSection(strSection, strBuffer, 512, strFile)
strTemp = Left$(strBuffer, intSize)
Do Until Len(strTemp) = 0
intTemp = InStr(1, strTemp, Chr(0))
ReDim Preserve arrSection(1, Index) As String
str = Mid(strTemp, 1, intTemp)
key = Mid(str, 1, InStr(1, str, "=") - 1)
value = Mid(str, InStr(1, str, "=") + 1)
arrSection(0, Index) = key
arrSection(1, Index) = value
Index = Index + 1
strTemp = Mid(strTemp, intTemp + 1, Len(strTemp))
Loop
GetSection = arrSection
PROC_EXIT:
Exit Function
PROC_ERR:
MsgBox "Ошибка:
<" & Err.Number & "> - " & Err.Description, _
vbExclamation +
vbOKOnly, "GetValueString"
Resume PROC_EXIT
End Function
Данная функция возвращает двумерный массив значений конкретной секции. Вначале, с помощью API-функции в буферизованную строку (strBuffer) считывается значение всей секции и определяется количество знаков (intSize). Далее, обрезаем строку от пустот и передаем это значение переменной strTemp. Затем в цикле Do-Loop считываем значение каждой строки (они разделены символом Chr(0)) и, предварительно разделив их на имя ключа и его значение, сбрасываем в двумерный массив. Первый параметр в массиве – будет означать, что мы считываем: имя ключа (0) или его значение (1).
Давайте сделаем маленький пример, чтобы стало понятнее, как работает наша функция. В качестве примера возьмем всем известную игру "Минер". Расположите на форме кнопку и список. При нажатии на кнопку в список последовательно передаются значения из секции [Сапер].
Private Sub Command1_Click()
Dim i As Integer, arrList As Variant
List1.Clear
arrList = GetSection("Сапер", "C:\Windows\winmine.ini")
For i = 0 To UBound(arrList, 2)
List1.AddItem arrList(1, i)
Next
End Sub
Обратите внимание, что если мы запишем arrList(0, i), то будем передавать уже не значения, а имена ключей.
Думаю на этом раздел, посвященный ini-файлам, можно закончить.
2001 г.
К статьям | Часть 1 | Листинг | Часть 3 |