Работа с файлами и каталогами

Очень часто нужно сохранить какие-либо данные. Для этого существует три способа: сохранение в файл, сохранение в базу данных и сохранение в реестр Windows. Первый способ используется при сохранении информации небольшого объема. Если объем велик, то лучше (и удобнее) воспользоваться базой данных. В реестр Windows обычно сохраняют какие-либо настройки приложения.

Открытие и закрытие файла

Прежде чем работать с файлом, необходимо создать объект файла с помощью инструкции Open. Инструкция имеет следующий формат:

Open <Имя файла> For <Режим> [Access <Доступ>] [<Блокировка>]
                 As [#]<Дескриптор> [Len=<Длина>]

В параметре <Имя файла> указывается путь к файлу. Путь может быть абсолютным или относительным. При указании относительного пути путь определяется с учетом местоположения текущего рабочего каталога, возвращаемого функцией CurDir(), а также текущего диска (сменить текущий диск позволяет процедура ChDrive()). Чтобы получить путь к папке, в которой находится файл с рабочей книгой, в Excel можно воспользоваться свойством Path объекта ThisWorkbook. Пример создания файла:

Open ThisWorkbook.Path & "\test.txt" For Output As #1

Параметр <Режим> может принимать следующие значения:

Параметр <Доступ> задает тип операции с открываемым файлом. Допустимые значения:

Необязательный параметр <Блокировка> может принимать следующие значения:

Параметр <Дескриптор> позволяет указать уникальный целочисленный номер файла в диапазоне от 1 до 511. Перед номером может быть добавлен символ #. Сгенерировать свободный уникальный номер позволяет функция FreeFile([<Значение>]). Если в параметре <Значение> задано значение 0, или параметр не указан, то генерируется число в диапазоне от 1 до 255, а если значение 1 — то генерируется число в диапазоне от 256 до 511. Пример использования функции FreeFile():

Dim fd As Integer
fd = FreeFile()
Open ThisWorkbook.Path & "\test.txt" For Output As #fd

В необязательном параметре <Длина> указывается целое число до 32 767. При использовании произвольного режима значение задает длину записи, а при использовании последовательного режима — размер буфера. Значение игнорируется в бинарном режиме.

Для закрытия файла используется инструкция Close. Формат инструкции:

Close [ [#]<Дескриптор1>[, ..., [#]<ДескрипторN>] ]

Инструкция закрывает файлы, дескрипторы которых перечислены через запятую. Если дескрипторы не указаны, то закрываются все открытые файлы. При завершении программы все открытые файлы автоматически закрываются.

Файлы могут быть открыты в трех режимах: последовательном, произвольном и бинарном. Рассмотрим эти режимы подробно.

Чтение и запись в последовательном режиме

Последовательный режим применяется при указании значений Input, Output и Append после ключевого слова For в инструкции Open. Запись в файл производится с помощью инструкции Write. Формат инструкции:

Write #<Дескриптор>, [<Значения>]

В параметре <Дескриптор> указывается номер файла, который использовался при открытии файла. В параметре <Значения> задаются записываемые значения через запятую, точку с запятой или через пробел (эквивалентно указанию точки с запятой). Если точка с запятой указывается в конце инструкции Write, то следующее выводимое значение будет вставляться на одной строке с предыдущим выводом через запятую, а не на новой строке. Если параметр <Значения> не указан, то вставляется пустая строка. Значения записываются в файл в следующих форматах:

Пример записи в файл:

Open ThisWorkbook.Path & "\test.txt" For Output As #1
Write #1, "Пример"     ' "Пример"
Write #1, "При""мер"   ' "При""мер"
Write #1, 10           ' 10
Write #1, 55.6         ' 55.6
Write #1, True         ' #TRUE#
Write #1, False        ' #FALSE#
Write #1, Null         ' #NULL#
Write #1, #8/20/2012#  ' #2012-08-20#
Write #1, True, 51     ' #TRUE#,51
Write #1, True; 51     ' #TRUE#,51
Write #1,              ' Пустая строка
Close #1

Чтение из файла производится с помощью инструкции Input. Формат инструкции:

Input #<Дескриптор>, <Список переменных через запятую>

В параметре <Дескриптор> указывается номер файла, который использовался при открытии файла. Во втором параметре задается список переменных, в которых сохранятся считываемые значения. Например, считать данные, записанные в предыдущем примере, можно следующим образом:

Dim v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13
Open ThisWorkbook.Path & "\test.txt" For Input As #1
Input #1, v1           ' "Пример"
Input #1, v2, v3       ' "При"   "мер"
Input #1, v4           ' 10
Input #1, v5           ' 55,6
Input #1, v6           ' True
Input #1, v7           ' False
Input #1, v8           ' Null
Input #1, v9           ' 20.08.2012
Input #1, v10, v11     ' True  51
Input #1, v12, v13     ' True  51
Close #1

Обратите внимание на четвертую инструкцию. Ранее мы записывали строку, в состав которой входит двойная кавычка. При считывании одна строка разбивается на две подстроки. В результате переменная v2 будет иметь значение "При", а переменная v3 — значение "мер".

Для записи в файл можно воспользоваться также инструкцией Print. Формат инструкции:

Print #<Дескриптор>, [<Значения>]

В параметре <Дескриптор> указывается номер файла, который использовался при открытии файла. В параметре <Значения> задаются записываемые значения через запятую, точку с запятой или через пробел (эквивалентно указанию точки с запятой). Если указывается запятая, то следующее значение выводится в начале следующей зоны (по умолчанию начало зоны расположено в каждом 14-ом столбце), а если точка с запятой — то следующее значение выводится сразу после предыдущего:

Print #1, "1", "2", "3"  ' 1             2             3
Print #1, "1"; "2"; "3"  ' 123

Если точка с запятой указывается в конце инструкции Print, то следующее выводимое значение будет вставляться на одной строке с предыдущим выводом, а не на новой строке. Если параметр <Значения> не указан, то вставляется пустая строка. Значения записываются в файл в следующих форматах:

Пример записи в файл:

Open ThisWorkbook.Path & "\test.txt" For Output As #1
Print #1, "Пример"     ' Пример
Print #1, "При""мер"   ' При"мер
Print #1, 10           ' 10
Print #1, 55.6         ' 55,6
Print #1, True         ' True
Print #1, False        ' False
Print #1, Null         ' Null
Print #1, #8/20/2012#  ' 20.08.2012
Print #1, True, 51     ' True           51
Print #1, True; 51     ' True 51
Print #1,              ' Пустая строка
Close #1

Второй параметр может содержать следующие функции:

Print #1, "1"; Spc(5); "2"   ' 1     2
Print #1, "1"; Spc(10); "2"  ' 1          2
Print #1, "1", "2"       ' 1             2
Print #1, "1"; Tab; "2"  ' 1             2

Параметр <Количество> задает номер столбца, с которого начинается вывод:

Print #1, """"; Tab(10); "1"; """"  ' "        1"

Прочитать файл, записанный с помощью инструкции Print, позволяет инструкция Line Input. Чтение производится построчно при каждом вызове инструкции. Формат инструкции:

Line Input #<Дескриптор>, <Переменная>

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

Dim s As String
Open ThisWorkbook.Path & "\test.txt" For Input As #1
Line Input #1, s
Debug.Print s          ' Пример
Line Input #1, s
Debug.Print s          ' При"мер
Close #1

Чтобы прочитать все строки из файла следует воспользоваться функцией EOF(<Дескриптор>). Функция возвращает значение True, если был достигнут конец файла, и False — в противном случае. Вывести все строки из файла позволяет следующий код:

Dim s As String
Open ThisWorkbook.Path & "\test.txt" For Input As #1
Do While Not EOF(1)
   Line Input #1, s
   Debug.Print s
Loop
Close #1

Инструкция Width позволяет указать предпочитаемую ширину строки. Формат инструкции:

Width #<Дескриптор>, <Ширина>

Параметр <Ширина> может содержать значения в диапазоне от 0 до 255. Если указано значение 0, то ширина не ограничена. Если длина строки больше указанного значения, то значение игнорируется и строка выводится полностью. Пример указания ширины, равной трем символам:

Dim i As Integer
Open ThisWorkbook.Path & "\test2.txt" For Output As #1
Width #1, 3
For i = 1 To 9
   Print #1, CStr(i);
Next
Print #1, "Очень длинная строка"
Close #1
' Результат:
' 123
' 456
' 789
' Очень длинная строка

Для чтения файла можно также воспользоваться функцией Input(<Количество символов>, [#]<Дескриптор>), которая читает из файла указанное количество символов и возвращает их. Пример:

Open ThisWorkbook.Path & "\test2.txt" For Output As #1
Print #1, "строка"
Close #1

Open ThisWorkbook.Path & "\test2.txt" For Input As #1
Debug.Print Input(1, #1) ' с
Debug.Print Input(5, #1) ' трока
Close #1

Чтение и запись в произвольном режиме

Произвольный режим применяется при указании значения Random после ключевого слова For в инструкции Open. Длина записи в произвольном режиме является фиксированной и задается с помощью параметра <Длина> (целое число до 32 767) в инструкции Open. При чтении и записи длина должна быть указана одинаковой. Запись в файл производится с помощью инструкции Put. Формат инструкции:

Put [#]<Дескриптор>, [<Позиция>], <Значение>

В параметре <Дескриптор> указывается номер файла, который использовался при открытии файла. В параметре <Позиция> задается номер позиции (нумерация начинается с 1) в которую производится запись. Если параметр не указан, то запись производится в следующую позицию после текущей позиции. Параметр <Значение> задает записываемое значение. Если длина значения больше длины, указанной в параметре <Длина>, то генерируется ошибка. Если производится запись строки произвольной длины, то значение в параметре <Длина> должно быть на 2 байта больше фактической длины строки. Пример записи в файл:

Open ThisWorkbook.Path & "\test3.txt" For Random As #1 Len = 10
Put #1, , 123456
Put #1, , 12.5
Put #1, , "строка"
Close #1

Чтение файла производится с помощью инструкции Get. Формат инструкции:

Get [#]<Дескриптор>, [<Позиция>], <Переменная>

В параметре <Дескриптор> указывается номер файла, который использовался при открытии файла. В параметре <Позиция> задается номер позиции (нумерация начинается с 1) из которой производится чтение. Если параметр не указан, то читаются данные из следующей позиции после текущей позиции. Пример:

Dim v1 As Long, v2 As Double, v3 As String
Open ThisWorkbook.Path & "\test3.txt" For Random As #1 Len = 10
Get #1, , v1
Get #1, , v2
Get #1, , v3
Close #1
Debug.Print v1, v2, v3 ' 123456        12,5         строка

Чтение и запись в бинарном режиме

Бинарный режим применяется при указании значения Binary после ключевого слова For в инструкции Open. Длина записи в бинарном режиме является фиксированной и равна одному байту. Если указано значение в параметре <Длина>, то это значение игнорируется.

Чтение и запись в бинарном режиме осуществляется точно также, как и при использовании произвольного режима. Прочитать данные из файла позволяет инструкция Get, а записать данные инструкция Put. В параметре <Позиция> в этих инструкциях указывается порядковый номер байта.

Пример записи строки в файл:

Open ThisWorkbook.Path & "\test4.txt" For Binary As #1
Put #1, , "строка"
Close #1

Пример чтения строки из файла:

Dim s As String
Open ThisWorkbook.Path & "\test4.txt" For Binary As #1
s = Space(LOF(1))
Get #1, , s
Close #1
Debug.Print s ' строка

В этом примере мы воспользовались функцией LOF(<Дескриптор>), которая позволяет получить длину файла в байтах. Чтобы считать данные из бинарного файла в строковую переменную необходимо в переменной создать строку такого же размера. В данном случае мы с помощью функции Space() создаем строку из такого же количества символов, что и размер файла. Обратите внимание на то, что использовать функцию EOF() в бинарном режиме нельзя, так как она всегда возвращает значение False.

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

Запишем строку в бинарный файл, а затем считаем ее с помощью функции Input():

Open ThisWorkbook.Path & "\test5.txt" For Binary As #1
Put #1, , "строка"
Close #1

Open ThisWorkbook.Path & "\test5.txt" For Binary As #1
Debug.Print Input(1, #1) ' с
Debug.Print Input(5, #1) ' трока
Close #1

Перемещение указателя внутри файла

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

Запишем строку в файл в бинарном режиме, а затем переместим указатель в начало файла и считаем содержимое файла посимвольно в строку (листинг 12.1).

Листинг 12.1. Перемещение указателя внутри файла

Dim s As String, pos As Long
Open ThisWorkbook.Path & "\test4.txt" For Binary As #1
Put #1, , "строка"
Debug.Print Loc(1), Seek(1) ' 6             7
Seek #1, 1                  ' Перемещаем в начало файла
Debug.Print Loc(1), Seek(1) ' 0             1
Do While pos < LOF(1)       ' Считываем по одному байту
    s = s & Input(1, #1)
    pos = Loc(1)
Loop
Close #1
Debug.Print s               ' строка

Чтение и запись файлов в кодировке UTF-16

Все строки, которые мы записывали ранее, сохранялись в файле в кодировке, принятой в системе по умолчанию. В моем случае в кодировке Windows-1251. Если необходимо записать данные в кодировке UTF-16 или прочитать данные, то можно воспользоваться функцией StrConv() (см. разд. 6.8) для преобразования кодировки. В качестве примера запишем данные в фай, а затем прочитаем и выведем их (листинг 12.3).

Листинг 12.2. Чтение и запись файлов в кодировке UTF-16

Dim s As String
s = "строка"
s = Chr(255) & Chr(254) & StrConv(s, vbUnicode, 1049)
Open ThisWorkbook.Path & "\enc.txt" For Binary As #1
Put #1, , s
Close #1

Open ThisWorkbook.Path & "\enc.txt" For Binary As #1
s = Space(LOF(1) - 2)
Seek #1, 3
Get #1, , s
Close #1
s = StrConv(s, vbFromUnicode, 1049)
Debug.Print s ' строка

Обратите внимание на инструкцию

s = Chr(255) & Chr(254) & StrConv(s, vbUnicode, 1049)

Комбинация символов с кодами 255 и 254 является меткой порядка байтов (сокращенно BOM (Byte Order Mark)). Эта метка является обязательной для кодировки UTF-16. При чтении данных мы пропускаем их и начинаем чтение с позиции 3.

Чтение и запись файлов в кодировке UTF-8

Работа с файлами в кодировке UTF-8 выполняется сложнее. В этом случае необходимо воспользоваться функциями MultiByteToWideChar() и WideCharToMultiByte(), входящими в состав Win32 API. Чтобы это стало возможным, нужно в самом начале модуля вставить следующий код:

Private Declare Function MultiByteToWideChar Lib "kernel32.dll" _
       (ByVal CodePage As Long, ByVal dwFlags As Long, _
        ByVal lpMultiByteStr As String, ByVal cchMultiByte As Long, _
        ByVal lpWideCharStr As Long, ByVal cchWideChar As Long) As Long
Private Declare Function WideCharToMultiByte Lib "kernel32.dll" _
       (ByVal CodePage As Long, ByVal dwFlags As Long, _
        ByVal lpWideCharStr As Long, ByVal cchWideChar As Long, _
        ByVal lpMultiByteStr As Long, ByVal cchMultiByte As Long, _
        ByVal lpDefaultChar As Long, ByVal lpUsedDefaultChar As Long) _
        As Long

Далее создадим две функции: ToUtf8() (для преобразования строки в кодировку UTF-8) и FromUtf8() (для преобразования кодировки UTF-8 в Unicode):

Public Function ToUtf8(ByVal s As String) As String
    Dim n As Long, res As String
    res = String$(Len(s) * 2, vbNullChar)
    n = WideCharToMultiByte(65001, &H0, StrPtr(s), Len(s), _
                            StrPtr(res), Len(s) * 2, 0&, 0&)
    ToUtf8 = Left$(StrConv(res, vbUnicode), n)
End Function

Public Function FromUtf8(ByVal s As String) As String
    Dim n As Long, res As String
    res = String$(Len(s), vbNullChar)
    n = MultiByteToWideChar(65001, &H0, s, Len(s), StrPtr(res), _
                            Len(res))
    FromUtf8 = Left$(res, n)
End Function

Теперь мы можем пользоваться этими функциями для чтения и записи файлов в кодировке UTF-8:

Dim s As String
s = "строка"
s = ToUtf8(s)
Open ThisWorkbook.Path & "\utf8.txt" For Binary As #1
Put #1, , s
Close #1

Open ThisWorkbook.Path & "\utf8.txt" For Binary As #1
s = Space(LOF(1))
Get #1, , s
Close #1
s = FromUtf8(s)
Debug.Print s ' строка
Предыдущая статья Все статьи Следующая статья