gifts2017

INI-Файлы

Опубликовал Роман Грук (gruk) в раздел Программирование - Практика программирования

Да, устарели. Морально и физически.
Не пинайте, просто понадобилось.

Перед публикацией прочитал статью "Работа с INI-файлами"  http://infostart.ru/public/85150/

Подумал: "Ну хоть не я один мамонтов реинкарнирую" :)

Хотя даже скептики признают удобство и простоту редактирования этих файлов.

 

Поддержка INI-файлов выполнена в виде функций общего модуля.

При открытии инифайла создается структура, где ключи - это названия секций, а значения - структуры с парами ключ-значение из соответствующей секции файла.

Структуру я выбрал из-за удобства работы с ней, несмотря на ограничения, что ключи должны удовлетворять требованиям, предъявляемым к именованию переменных встроенного языка.

Вот функции открытия и записи INI файла

 

// Читает INI файл в структуру и возвращает ее.
// При отсутствии файла возвращает пустую структуру
//  по умолчанию - КодировкаТекста.ANSI
//  показывает в какой строке произошла ошибка чтения
Функция Открыть(Файл, Кодировка = Неопределено, Отладка = Истина) Экспорт
	СтруктураИни = Новый Структура;
	Если Кодировка = Неопределено Тогда
		Кодировка = КодировкаТекста.ANSI;
	КонецЕсли;
	Попытка
		Текст = Новый ЧтениеТекста(Файл, Кодировка);
	Исключение
		Возврат Новый Структура;//Неопределено;
	КонецПопытки;
	
	Группа = Неопределено;
	Стр = Текст.ПрочитатьСтроку();
	НомерСтр = 1;
	Пока Стр <> Неопределено Цикл 		// строки читаются до символа перевода строки
		Стр = СокрЛП(Стр);
		Если Лев(Стр, 1) = ";" Или ПустаяСтрока(Стр)  Тогда		//Игнорируем комментарий
			//Перейти ~Следующий;
		ИначеЕсли Лев(Стр, 1) = "[" Тогда	//Нашли секцию
			Если Прав(Стр, 1) <> "]" Тогда
				Если Отладка Тогда
					Сообщить ("Ошибка синтаксиса формата INI: Строка " + НомерСтр);
				КонецЕсли;
				Возврат Неопределено;
			КонецЕсли;
			Группа = Сред(Стр, 2, СтрДлина(Стр) - 2);
			СтруктураИни.Вставить(Группа, Новый Структура);
		Иначе								//Параметр
			ПозицияРавно = Найти(Стр, "=");
			Если Группа = Неопределено ИЛИ ПозицияРавно = 0 Тогда
				Если Отладка Тогда
					Сообщить ("Ошибка синтаксиса формата INI: Строка " + НомерСтр);
				КонецЕсли;
				Возврат Неопределено;
			КонецЕсли;
			Значение = Сред(Стр, ПозицияРавно + 1);
			СтруктураИни[Группа].Вставить(Лев(Стр, ПозицияРавно - 1), ?(ПустаяСтрока(Значение), Неопределено, Значение));
		КонецЕсли;
		
		//~Следующий:
    	Стр = Текст.ПрочитатьСтроку();
		НомерСтр = НомерСтр + 1;
	КонецЦикла;
	Возврат СтруктураИни;
КонецФункции

// Сохраняет структуру в ини файл. Ключи структуры сохраняются как названия секций,
// Если значением структуры является структура, то ее ключи сохраняются в эту секцию как
// названия параметров, значения как значения параметров.
// Если элемент структуры не строка или не структура, он будет пропущен
//  - Задает расширение файла для резервного копирования INI файла перед записью (Можно сточкой или без)
Функция Сохранить(Ини, Файл, Знач Резерв = Неопределено, Кодировка = Неопределено) Экспорт
	Если Не ПустаяСтрока(Резерв) Тогда
		ВыводИни = Новый  Файл(Файл);
		Если ВыводИни.Существует() Тогда
			Если Лев(Резерв, 1)  <> "." Тогда
				Резерв = "." + Резерв;
			КонецЕсли;
			КопироватьФайл(Файл, ВыводИни.Путь + ВыводИни.ИмяБезРасширения + Резерв);
		КонецЕсли;
		ВыводИни = Неопределено;
	КонецЕсли;
	
	Если Кодировка = Неопределено Тогда
		Кодировка = КодировкаТекста.ANSI;
	КонецЕсли;
	ВыводИни = Новый ЗаписьТекста(Файл, Кодировка);
	Для Каждого Секция Из Ини Цикл
		Если ТипЗнч(Секция.Значение) <> Тип("Структура") Тогда
			Продолжить;
		КонецЕсли;
		ВыводИни.ЗаписатьСтроку("[" + Секция.Ключ + "]");
		Для Каждого Параметр Из Секция.Значение Цикл
			Если ТипЗнч(Параметр.Значение) <> Тип("Строка") Тогда
				Продолжить;
			КонецЕсли;
			ВыводИни.ЗаписатьСтроку(Параметр.Ключ + "=" + Параметр.Значение);
		КонецЦикла;
		ВыводИни.ЗаписатьСтроку("");
	КонецЦикла;
	ВыводИни.Закрыть();
КонецФункции

 

Пример работы со структурой 

Ини = ИниФайл.Открыть("С:\ИниФайл.ini"); 
Значение = Ини.Секция.Параметр;

Так же есть возможность работы со структурой в стиле Delphi

// Базовая функция чтения строки.  Ини (Структура) - Структура INI файла,
//  Секция (Строка) - Имя секции,  Ключ (Строка) - Имя параметра,
//  Данные (Произвольный) - Будет возвращено, если секции или параметра
// не существует или значение параметра пустая строка
Функция ПолучитьСтроку(Ини, Секция, Ключ, Данные = Неопределено) Экспорт

// Базовая функция записи строки.  Ини (Структура) - Структура INI файла,
//  Секция (Строка) - Имя секции,  Ключ (Строка) - Имя параметра,
//  Данные (Произвольный) - в структуру будет записано строковое представление.
// Если секция или параметр не существует, то он будет создан.
Процедура ЗаписатьСтроку(Ини, Секция, Ключ, Данные) Экспорт 

Остальные функции работы с ключами структуры используют эти две функции и имеют те же основные параметры.

ПолучитьБулево, ЗаписатьБулево - Работает с разными представлениями записи логических переменных, можно задать своё.

ПолучитьЦелое, ЗаписатьЦелое - Целые так же могут быть в двоичном, шестнадцатеричном и восьмиричном представлении.

ПолучитьВещественное, ЗаписатьВещественное - Поддерживаются числа в полулогарифмической (нормальной) форме.

ПолучитьДатуВремя, ЗаписатьДатуВремя - В каноническом или локальном формате

ПолучитьДвоичныеДанные, ЗаписатьДвоичныеДанные - Пришлось записать картинку в одну строку, интересно, когда строка треснет?

Не реализованы Получить/Записать Дату, Время

Так же есть функции для работы с секциями.

 

// Возвращает число - количесво секций
Функция КоличествоСекций(Ини) Экспорт
	Возврат Ини.Количество();
КонецФункции

// Проверка существования секции, возвращает булево
Функция СекцияСуществует(Ини, Секция) Экспорт
	Возврат Ини.Свойство(Секция);
КонецФункции

// Удаляет секцию
Процедура УдалитьСекцию(Ини, Секция) Экспорт
	Ини.Удалить(Секция);
КонецПроцедуры

// Возвращает список секций в виде списка значений или в виде массива
Функция ПолучитьСекции(Ини, Массив = Ложь) Экспорт
	Секции = ?(Массив, Новый Массив, Новый СписокЗначений);
	Для Каждого Секция Из Ини Цикл
		Секции.Добавить(Секция.Ключ);
	КонецЦикла;
	Возврат Секции;
КонецФункции

// Возвращает список параметров в секции и их значений
// в виде Списка значений(Значение Функция ПолучитьСекцию(Ини, Секция) Экспорт
СтруктураСекция = Неопределено;
Если Не Ини.Свойство(Секция, СтруктураСекция) Тогда
Возврат Неопределено;
КонецЕсли;
Параметры = Новый СписокЗначений;
Для Каждого Параметр Из СтруктураСекция Цикл
Параметры.Добавить(Параметр.Ключ, Параметр.Значение);
КонецЦикла;
Возврат Параметры;
КонецФункции

// Возвращает список значений параметров в секции в виде
// списка значений (Значение Функция ПолучитьЗначенияСекции(Ини, Секция, Массив = Ложь) Экспорт
СтруктураСекция = Неопределено;
Если Не Ини.Свойство(Секция, СтруктураСекция) Тогда
Возврат Неопределено;
КонецЕсли;
Значения = ?(Массив, Новый Массив, Новый СписокЗначений);
Для Каждого Параметр Из СтруктураСекция Цикл
Значения.Добавить(Параметр.Значение);
КонецЦикла;
Возврат Значения;
КонецФункции

// Возвращает количество параметров в секции или Неопределено, если секция не существует
Функция КоличествоПараметров(Ини, Секция) Экспорт
СтруктураСекция = Неопределено;
Если Не Ини.Свойство(Секция, СтруктураСекция) Тогда
Возврат Неопределено;
КонецЕсли;
Возврат СтруктураСекция.Количество();
КонецФункции
Вобщем смотрите демку. Тестовый INI файл поместите в папку с базой.

Скачать файлы

Наименование Файл Версия Размер
Демо конфа 4
.cf 14,80Kb
04.09.15
4
.cf 14,80Kb Скачать
Демо INI-Файл
.ini 342,89Kb
04.09.15
0
.ini 342,89Kb Скачать

См. также

Подписаться Добавить вознаграждение
Комментарии
1. Сергѣй Батанов (baton_pk) 11.03.14 13:26
Поддержка INI-файлов выполнена в виде функций общего модуля.

Хм. А поддержка XML выполнена в виде встроенных механизмов платформы.

Единственное оправдание - если INI-файл нужен внешней программе (или клиенту, начальнику...), как например для файла nethasp.ini. Да и в этом случае лично я сделал бы чтение из INI-файла в структуру и запись, соответственно, структуры в INI-файл.
3. Роман Грук (gruk) 11.03.14 17:41
(1) baton_pk,
Да и в этом случае лично я сделал бы чтение из INI-файла в структуру и запись, соответственно, структуры в INI-файл.


я так и сделал, просто статья на скорую руку,может не очень понятно.
Сейчас поправлю.
4. Роман Грук (gruk) 11.03.14 18:35
(2) the1,
пользую IniEdit - плагин для тотал коммандера

Пользую Far Colorer для Far manager :)
5. Сергѣй Батанов (baton_pk) 11.03.14 21:16
Вот навернёте потом работу с булями, датами, числами, экранирование символов в строках, плюнете и начнёте использовать XML.

Структуру я выбрал из-за удобства работы с ней, несмотря на ограничения, что ключи должны удовлетворять требованиям, предъявляемым к именованию переменных встроенного языка.

Ещё можно воспользоваться Соответствием. Удобств не сильно меньше, просто вместо Ини.Секция.Параметр будет Ини["Секция"]["Параметр"].
6. Роман Грук (gruk) 12.03.14 04:08
(5) baton_pk,
Вот навернёте потом работу с булями, датами, числами, экранирование символов в строках

вы невнимательно читаете статью. були, даты, числа (в разных форматах) и даже двоичные данные (моя инициатива, просто хотел попробовать) сделаны. Просто не оформленны в статье в виде кода. На весь модуль у меня ушло несколько часов
плюнете и начнёте использовать XML.

XML пользую, серьезный обмен данными или сохранение большой кучи настроек без него трудоемко. Но, как вы правильно заметили в (1)
Единственное оправдание - если INI-файл нужен внешней программе (или клиенту, начальнику...)

поэтому не всегда так просто от него откреститься.
7. Роман Грук (gruk) 12.03.14 04:45
Вообще согласен, что поддержка INI на такой мощной и современной платформе выглядит рудиментарно. Правильно, что разработчики ее не сделали (хотя INI парсер есть почти во всех средах разработки), ведь за кажущейся простотой есть куча проблем в виде ограниченности уровней дерева параметров (хотя както был проектик, где пришлось это сделать. Несложно. Получился какойто недоXML), несовместимости и неоднозначности типа хранимых данных. А то пошли бы 1С-ники кто влес, кто по дрова.

Не по 1С:
А лично я до сих пор использую INI файлы для конфигурации устройств на микроконтроллерах собственной разработки.
Плюсы:
1. Парсер пишется просто, занимает мало места в (не резиновой) памяти (по сравнению с XML, или тем более WWW конфигом).
2. Не нужен какойто спец. софт для конфигурирования устройства (как в случае с конфигом в виде бинарника).
3. Редактирование любым подручным средством. Понятная конечному пользователю простая структура.
Минусы:
На слабеньких микроконтроллерах (типа AT90S1200 with 1K Byte of In-System Programmable Flash and 64 Bytes of In-System Programmable EEPROM) парсер и сам INI файл хранить практически не где. Тут только бинарный конфиг.
baton_pk; +1 Ответить
9. Марианенкова Наиля (donhenru) 01.12.15 13:41
Зачем пытаться загружать ini-файл в тип данных Структура?! ДеревоЗначений больше подходит. Из-за этого ваш алгоритм спотыкается если группа параметров с пробелами или с точками.

Вот, переделал:

СтруктураИни = Новый ДеревоЗначений;
	СтруктураИни.Колонки.Добавить("Параметр");
	СтруктураИни.Колонки.Добавить("Значение");
	
	Если Кодировка = Неопределено Тогда
		Кодировка = КодировкаТекста.ANSI;
	КонецЕсли;
	Попытка
		ТекстДок = Новый ЧтениеТекста(Файл, Кодировка);
	Исключение
		Возврат Неопределено;
	КонецПопытки;
	
	Группа = Неопределено;
	ВремСтр = ТекстДок.ПрочитатьСтроку();
	НомерСтр = 1;
	Пока ВремСтр <> Неопределено Цикл
		ВремСтр = СокрЛП(ВремСтр);
		Если Лев(ВремСтр, 1) = ";" Или ПустаяСтрока(ВремСтр)  Тогда
			//Закомментированная строка, пропускаем
		ИначеЕсли Лев(ВремСтр, 1) = "[" Тогда
			Если Прав(ВремСтр, 1) <> "]" Тогда
				Если Отладка Тогда
					Сообщить ("Ошибка синтаксиса формата INI: Строка " + НомерСтр);
				КонецЕсли;
				Возврат Неопределено;
			КонецЕсли;
			Группа = Сред(ВремСтр, 2, СтрДлина(ВремСтр) - 2);
			НовГруппа = СтруктураИни.Строки.Добавить();
			НовГруппа.Параметр = Группа;
		Иначе
			ПозицияРавно = Найти(ВремСтр, "=");
			Если Группа = Неопределено ИЛИ ПозицияРавно = 0 Тогда
				Если Отладка Тогда
					Сообщить("Ошибка синтаксиса формата INI: Строка " + НомерСтр);
				КонецЕсли;
				Возврат Неопределено;
			КонецЕсли;
			Значение = Сред(ВремСтр, ПозицияРавно + 1);
			НовПараметр = НовГруппа.Строки.Добавить();
			НовПараметр.Параметр = Лев(ВремСтр, ПозицияРавно - 1);
			НовПараметр.Значение = ?(ПустаяСтрока(Значение), Неопределено, Значение);
		КонецЕсли;
		
		ВремСтр = ТекстДок.ПрочитатьСтроку();
		НомерСтр = НомерСтр + 1;
	КонецЦикла;
	Возврат СтруктураИни;
...Показать Скрыть
10. Роман Грук (gruk) 02.12.15 08:03
(9) donhenru, Спасибо
У меня тоже как-то попался файл с именем параметра не "ВСтилеИмен1С", переделывал структуру на соответствие. А с деревом работать неудобно, нельзя обратиться ИНИ.ИмяСекции.ИмяПараметра