Работа с данными переменной длины
До сих пор мы усиленно подчеркивали, что при работе с файлом произвольного доступа размер записи фиксирован и это предполагает хранение в таких файлов данных, размер которых фиксирован в момент их объявления. На самом деле, это не так и в таких файлах можно хранить и строки переменной длины и данные типа Variant. В этих случаях просто следует быть более осторожным, поскольку из-за сложности правил хранения таких данных повышается возможность ошибки. Вот некоторые правила, согласно которым оператор Put размещает данные в файле, а оператор Get их читает:
- Данные всегда помещаются в файл, начиная с границ записей, установленных параметром Len при открытии файла. Если при этом длина данных, записываемых в файл, меньше размера записи, заданного параметром Len, оператор Put заполнит остающееся до длины записи место "случайными" данными из буфера файла, а новые данные поместит, начиная со следующей границы. При попытке записать данные, длина которых больше Len, появится сообщение об ошибке. Таким образом, параметр Len задает максимальный размер записи, внутри которого может храниться значение переменного размера.
- При записи строк переменной длины, переменных типа Variant, динамических массивов VBA помещает туда же дополнительную информацию для их расшифровки.
- При записи строки переменной длины Put помещает непосредственно перед ней 2 байта с ее длиной.
- Два дополнительных байта также помещаются в файл при записи переменной типа Variant. Их содержимое идентифицирует тип значения (как в функции VarType). Например, если оно равно 3, это соответствует типу Long, и запись такой переменной займет 6 байтов (2 - для типа и 4 - для самого числа). Значение VarType = 8 соответствует строковому типу (String). В этом случае Put запишет 2 байта с VarType, затем 2 байта с длиной строки и затем саму строку.
- В случае динамического массива Put записывает перед его элементами описатель с длиной 2 + 8* (число измерений массива).
- Массивы фиксированного размера записываются без описателей.
Без всякой дополнительной информации записываются и значения остальных типов переменных с фиксированными размерами. - Для бинарных файлов параметр Len при записи роли не играет. Put записывает значения переменных подряд без пропусков и не помещает длины динамических строк и дескрипторы массивов.
- Для переменных с нефиксированными размерами Get выполняет преобразования, обратные тем, что при записи выполнял оператор Put. Например, при чтении в строку переменной длины Get определяет по 2-байтовому описателю длину строки, а затем читает ее содержимое в переменную. Аналогичная расшифровка происходит и при чтении в переменные типа Variant и в динамические массивы.
- Для бинарных файлов Get читает данные подряд. В переменные фиксированного размера считывается соответствующее их размеру число байтов. При чтении в строку переменной длины в нее считывается число символов, равное длине ее текущего значения.
Приведем пример работы с файлом произвольного доступа, записи которого содержат данные не фиксированного размера:
Пример 14.6.
(html, txt)
Вот результаты ее работы:
Степанов 10 Архангельский 35 Куц 35 Петров 50 125,25 70 125 84
Приведем комментарии:
- Операторы Put и Get позволяют записать и корректно прочитать данные переменного размера, не превосходящего максимальный размер, заданный при открытии файла.
- При записи первой строки переменной длины размер файла стал равным 10 байтам, из которых 8 байтов занимает сама строка, а два байта, предшествующий ей описатель. Описатель позволяет оператору Get корректно прочитать эту строку.
- Запись второй строки начинается с 21-го байта, границы первой записи, общий размер файла становится равным 35 с учетом размера второй строки и ее описателя.
- Третья запись не изменяет размера файла, поскольку происходит изменение значения первой записи, так что файл по-прежнему содержит только две записи.
- Далее начинается запись данных типа Variant. Теперь при записи строки используются два описателя, занимающие 4 байта.
- Две последние записи содержат числовые данные Double (8 байтов) и Integer (2 байта) с их описателями.
Заканчивая тему работы с файлами произвольного доступа, хотим еще раз обратить внимание на некоторые опасные моменты, возникающие в процессе работы с ними и не контролируемые VBA:
- Явно задавайте при открытии файла, как при чтении, так и при записи параметр Len ѕ максимальный размер записи. Если этого не сделать, то программа будет работать, но, к сожалению, результаты могут быть не предсказуемыми.
- Будьте особенно внимательными при работе с данными переменной длины, помните, что к данным автоматически присоединяются описатели.
- Размер файла определяется записью с максимальным номером. Чтобы избежать большого числа "дырок" в файле стройте разумные функции ключа так, чтобы ключи записей занимали достаточно плотный начальный интервал от 1 до N.
Описатель позволяет оператору Get корректно прочитать эту строку.
Запись второй строки начинается с 21-го байта, границы первой записи, общий размер файла становится равным 35 с учетом размера второй строки и ее описателя.Третья запись не изменяет размера файла, поскольку происходит изменение значения первой записи, так что файл по-прежнему содержит только две записи.Далее начинается запись данных типа Variant. Теперь при записи строки используются два описателя, занимающие 4 байта.Две последние записи содержат числовые данные Double (8 байтов) и Integer (2 байта) с их описателями.
Заканчивая тему работы с файлами произвольного доступа, хотим еще раз обратить внимание на некоторые опасные моменты, возникающие в процессе работы с ними и не контролируемые VBA:
- Явно задавайте при открытии файла, как при чтении, так и при записи параметр Len ѕ максимальный размер записи. Если этого не сделать, то программа будет работать, но, к сожалению, результаты могут быть не предсказуемыми.
- Будьте особенно внимательными при работе с данными переменной длины, помните, что к данным автоматически присоединяются описатели.
- Размер файла определяется записью с максимальным номером. Чтобы избежать большого числа "дырок" в файле стройте разумные функции ключа так, чтобы ключи записей занимали достаточно плотный начальный интервал от 1 до N.
Содержание раздела