Тема: JScript: модуль обработки INI файлов и утилита работы с INI файлами
Получилось большое сообщение. Поэтому в ходе ее написания я решил ее разделить на три отдельных части. Первая часть дает описание модуля, иллюстрируя его возможности примерами кода. Вторая часть - это текст самого модуля. Из текста модуля были удалены англоязычные комментарии. Приведена ссылка на полный текст модуля. Третья часть - описание и исходный текст полноценного приложения, разработанного в качестве иллюстрации работы модуля.
Описание модуля обработки INI файлов
Представляю сообществу модуль подготовки данных для чтения/записи в INI файлы. Этот пост отражает мое видение решения задачи - каждое действие должно отрабатываться на определенной стадии и должно существовать определенное "разделение труда" между функциями. То есть функции чтения и записи не должны выполнять какие-либо другие действия кроме работы с файловой системой. Верно и обратное, функции обработки данных не должны выполнять действий, связанных с файловой системой.
-- Это первое отличие данного решения от аналогичного, предложенного в теме JScript: чтение INI файлов - обработка данных и чтение/запись в файл разделены.
-- Второе отличие заключается в том, что здесь предлагается более гибкая реализация обработки данных. Так, данные могут поступать в функцию в виде большой строковой переменной, массива или функции, которая возвращает содержимое INI файла строка за строкой.
-- Третье отличие заключается в большей гибкости при работе с множественной вложенностью (будет рассмотрена далее).
-- Четвертое - код корректно обрабатывает одноименные ключи в одном разделе и при преобразовании в сохраняет их в виде массива. Аналогично, метод INI.stringify "знает" как обойтись с этим массивом.
Хотя при этом код увеличился примерно в 2 раза, по сравнению с ранее упомянутым решением (сравнение производилось над файлами с полностью удаленными комментариями, в качестве отступов использовались символы табуляции), однако скорость выполнения практически не пострадала, и существенно была улучшена функциональность модуля. Так файл объемом более 2МБ (примерно около 50 тыс. строк, это реальный файл) был обработан примерно за одинаковое время - около 1500-1900 мс.
Модуль предоставляет глобальный объект INI, содержащий два метода parse и stringify. Знакомые с JSON узнают названия этих методов - их функциональность аналогична. Отличие заключается в строковом представлении обрабатываемых объектов.
INI.stringify(value, levelDelimiter)
Метод берет объект value и преобразует в текстовое представление. Необязательный строковый параметр levelDelimiter задает символ, используемый для разделения имен вложенных узлов друг от друга. Значение по умолчанию - символ слэш - '/'.
INI.parse(text, levelDelimiter, deepen)
Метод преобразует текст, переданный параметром text в объект. Значение строкового параметра levlDelimiter аналогично предыдущему - задать символ, который разделяет имена вложенных узлов. Третий логический параметр, тоже необязательный, указывает как необходимость создания вложенной структуры.
Обычно INI файл это текстовый файл имеющий примерно такой вид:
Текст 1
[section1]
key1=value1
key2=value2
[section2]
key3=value3
key4=value4
который программно может быть преобразован в такую структуру:
Код 1
var iniObj = {
section1: {
key1: 'value1',
key2: 'value2'
},
section2: {
key3: 'value3',
key4: 'value4'
}
}
Верно и обратное - подобная структура может быть преобразована в текстовый формат без нарушения отношений между хранимыми элементами.
Рассмотрим пример.
Текст 2
[section1]
key1=value1
key2=value2
[section1/section2]
key3=value3
key4=value41
key4=value42
[section3]
key5=value5
key6=value6
Пусть содержимое этого текстового файла было считано в переменную iniTxt.
var iniTxt = <...>
var iniObj = INI.parse(iniTxt);
Этот код создаст объект такого вида. Для манипуляции с узлами и ключами необходимо использовать "скобочную" нотацию - iniObj['section1/section2']['key3']:
Код 2.1
var iniObj = {
section1: {
key1: 'value1',
key2: 'value2',
'section1/section2': {
key3: 'value3',
key4: [
'value41',
'value42'
]
},
section3: {
key5: 'value5',
key6: 'value6'
}
}
Однако, при указании параметра deepen == true объект будет отличаться.
var iniTxt = <...>
var iniObj = INI.parse(iniTxt, '/', true);
И результат работы этого скрипта ниже. Для манипуляции с узлами и ключами можно использовать как "скобочную", так и "точечную" нотацию - iniObj.section1.section2.key3:
Код 2.2
var iniObj = {
section1: {
key1: 'value1',
key2: 'value2',
section2: {
key3: 'value3',
key4: [
'value41',
'value42'
]
}
},
section3: {
key5: 'value5',
key6: 'value6'
}
}
Как было сказано ранее - параметр text метода INI.parse может принимать один из трех возможных типов данных - строку, массив или функцию.
Передаваемая строка разбивается делится построчно по символу "перевод строки" на отдельные строки и обрабатывается строка за строкой.
var iniObj = INI.parse('...');
Массив содержит отдельные строки. Метод обходит все строки и разбирает их в объект.
var iniObj = INI.parse(['...', '...' ...]);
Функция - это генератор строк, который должен вернуть значение null как индикатор окончания входных данных. Этот способ может быть полезен при обработке большого или непрерывного потока данных. Далее полный пример, поясняющий принцип работы функции
function readIniFile(filename)
{
var fso = new ActiveXObject('Scripting.FileSystemObject');
var f = fso.GetFile(filename);
var h = f.OpenAsTextStream(1);
iniObj = INI.parse(function()
{
return h.AtEndOfStream ? null : h.ReadLine();
});
h.Close();
};