[Include] [INC] mxINI - Самый быстрый INI ридер/райтер
#1

Что это за скрипт
  • Это релиз инклуд-файла с инструментами для самого быстрого чтения/записи INI файлов. Более того, этот инклуд не нуждается в настройке. Вы подключаете его в ФС или МОД и можно сразу читать/записывать INI файлы.

Преимущества
  • Свободный формат
    Во-первых, оформлять ваши INI файлы вы можете как угодно - криво/ровно, с отступами/без, с комментами/без, с любыми пробельными символами вокруг =. И это все никак не влияет на чтение/запись. Нет никаких лимитов на длину ключей или значений. Ключи и значения можно писать даже по-русски. В имени ключа/значении можно использовать любые символы кроме \r и \n. Пробелы и знаки табуляции вокруг имени ключа, вокруг символа = и перед текстовым значением считаются отступами. В одной строке вы можете поместить любое кол-во пар ключ/значение, включая всевозможные варианты оформления.

  • Свободное расположение комментов
    Чтобы увеличить скорость чтения, считается, что любые строки, где нет символа = это комментарии. Также комментарием может быть любой текст, все зависит от вашего форматирования.

  • Скорость
    Перед тем как читать что-то из INI файла, его также как и остальные файлы нужно открыть. При открытии весь файл копируется в ОЗУ вместе с именем. Остальные операции чтения/записи производятся непосредственно в ОЗУ. Именно поэтому все это происходит очень быстро. Если контент файла в ОЗУ был изменен, при закрытии он будет записан на диск.

    Еще 1 плюс, который ранее в скриптинге не применялся - это сжатое хранение контента файла, что в 4 раза меньше, чем обычный формат. Скорость также достигается за счет отсутствия дополнительных функций, которые могли бы использоваться в функциях чтения/записи, а также за счет использования только встроенных функций скриптинга.

Инструменты
  • ini_createFile ( "путь/к/файлу.ini", "Содержимое файла по умолчанию" )
  • ini_openFile ( "путь/к/файлу.ini" )
  • ini_closeFile ( ИД_открытого_файла )

  • ini_setString ( ИД_открытого_файла, "имя ключа", "текстовое значение" )
  • ini_setInteger ( ИД_открытого_файла, "имя ключа", 123456 )
  • ini_setFloat ( ИД_открытого_файла, "имя ключа", 3.1416 )

  • ini_getString ( ИД_открытого_файла, "имя ключа", returnValue )
  • ini_getInteger ( ИД_открытого_файла, "имя ключа", returnValue )
  • ini_getFloat ( ИД_открытого_файла, "имя ключа", returnValue )

  • ini_removeKey ( ИД_открытого_файла, "имя ключа" )
  • ini_getErrorInfo ( Код_ошибки )

Примеры
Код:
new iniFile = ini_createFile ( "test4268.ini" );

if ( iniFile < 0 )
	iniFile = ini_openFile ( "test4268.ini" );

if ( iniFile >= 0 )
{
	new returnString[32], returnNumber, Float: returnFloat;

	ini_setString ( iniFile, "ключ со строкой", "текстовое значение" );
	ini_setInteger ( iniFile, "ключ с числом",  123456 );
	ini_setFloat  ( iniFile, "ключ с дробью",  3.1416 );

	ini_removeKey ( iniFile, "ключ с числом" );

	ini_getString ( iniFile, "ключ со строкой", returnString );
	ini_getInteger ( iniFile, "ключ с числом",  returnNumber );
	ini_getFloat  ( iniFile, "ключ с дробью",  returnFloat );


	ini_closeFile ( iniFile );

	printf ( "\n `ключ_со_строкой` = `%s`,\n `ключ_с_числом` = `%d`,\n `ключ_с_дробью` = `%f` \n",
		returnString, returnNumber, returnFloat );
}
else print( "\n Не удалось открыть INI файл \n" );
Тест
  • ТЕСТ скорости 2-х библиотек, которые ориентированы исключительно
    на чтение/запись в файлы INI формата.

    Тестируются: Dini, mxINI

    Для тестирования из библиотек будут использоваться только самые быстрые
    функции чтения/записи для строк, т.к. скорость преобразования типов зависит
    не от инструментов библиотеки, а от встроенных функций скриптинга.

    Каждой библиотеке нужно будет создать и открыть INI файл, записать в него 100 ключей,
    прочесть значения этих ключей, закрыть файл.

    Это результаты выполнения вышеуказанных операций. Сравните их.

    1 секунда = 1000 милисекунд (мсек)


    ФС для тестирования

Ссылки Возможные недочеты, если они есть, опишите здесь.
Опубликовано только в русском разделе, буржуИны ыдут лесом, кроме ******, стессна ((:
Reply
#2

очень интересно...
Quote:
Originally Posted by MX_Master
Если контент файла в ОЗУ был изменен, при закрытии он будет записан на диск.
а если сервер упадет с ошибкой?
и быстрее ли это чем mysql?
Reply
#3

Мм, а запись в файл как я понимаю отсутствует? Ибо я не нашёл...
Reply
#4

а секции ини поддерживаются? я еще не видел ни разу библиотеки, которая работала бы с секциями.
это типа переделанный под ини djson, верно?
и что за сжатое хранение? подробнее?
Reply
#5

О, я рад что к релизу есть интерес, чесслово. Отвечу по порядку поступления вопросов.

Quote:
Originally Posted by Serafim_sd
очень интересно...
Quote:
Originally Posted by MX_Master
Если контент файла в ОЗУ был изменен, при закрытии он будет записан на диск.
а если сервер упадет с ошибкой?
и быстрее ли это чем mysql?
Если INI файл во время падения сервера был не закрыт, естессна, он на диск не запишется. Поэтому даже в английской части форума, корефеи скриптинга советуют всем закрывать открытые файлы, или базы данных sqlite, если они более не нужны по ходу скрипта. Самым ярким примером неправильного использования является открытие файла или БД при старте игрового режима и закрытие его при завершении. Именно такой способ часто порождает сбой в записываемых данных. Хотя тут может быть исключение - если INI файл не планируется изменять, его можно открыть в начале мода, а закрыть в конце, или вовсе не закрывать. В этом случае данные не потеряются и не испортятся на диске. Все вышесказанное не касается MySQL, т.к. это отдельно работающий процесс.

Я чесслово, не проводил сравнение скорости чтения и нагрузки на процессор INI ридера/райтера и бд MySQL, т.к. MySQL это все-таки отдельный процесс, а чтение/запись INI файлов выполняет самп сервер. Я думаю, если данных в INI файле немного, INI ридер получит их быстрее, но это только догадки.


Quote:
Originally Posted by Alone_MAF1A
Мм, а запись в файл как я понимаю отсутствует? Ибо я не нашёл...
все верно, в течение нескольких дней функция записи будет добавлена, в том числе и запись/чтение значений Integer и Float.


Quote:
Originally Posted by xomka
а секции ини поддерживаются? я еще не видел ни разу библиотеки, которая работала бы с секциями.
это типа переделанный под ини djson, верно?
и что за сжатое хранение? подробнее?
Насколько мой опыт подсказывает, для игрового сервера нужны INI файлы небольшого размера, но их кол-во может быть довольно большим. Этим я хочу сказать, что секции в небольших файлах как таковые не нужны и их логически можно разделить на несколько файлов. Тем не менее, если кому-то действительно как воздух нужны секции в INI файлах, я позднее сделаю отдельную версию, т.к. скорость ее работы заметно увеличится.

Это написанный с 0 скрипт, не имеющий отношения к другим подобным библиотекам. Если в механизмах этого скрипта есть сходства с другими библиотеками, то наверное потому, что чтение и разбор данных из файла примерно везде одинаковый, разница только в логике.

PAWN может хранить строки как в обычном виде, так и в сжатом. В обычной строке для 1 символа отводится 4 байта, он может хранить и UTF8 символы. В сжатой строке 1 символ занимает всего 1 байт. Я отдал предпочтение сжатому (бинарному) виду, что ЗНАЧИТЕЛЬНО сокращает расход ОЗУ.
Reply
#6

все ясно возможно, если будет эффективным, таки перейду на этот вместо старого дини

вот как пример, кусок аккаунта, где секции очень пригодились бы
Код:
player.nicks=cookies
player.time=0
player.links=
player.password=lol

stats.kills=0
stats.deaths=10

saved.hp=85.000000
saved.ap=0.000000
вместо раздел.данные=значения очень удобно было бы загонять данные вот в такой вид:
Код:
[PLAYER]
nicks=cookies
time=0
links=
password=lol

[STATS]
kills=0
deaths=10

[SAVED]
hp=85.000000
ap=0.000000
и кстати, не забудьте про установку значений в типе Float
Reply
#7

если я правильно понял, то в этом примере секции нужны только, чтобы при ручном редактировании видеть разные группы ключей. Не в одной из этих групп нет одинаковых ключей! Т.е. в этом примере ваще использование секций не только не оправдано, оно вовсе не нужно. Чтобы вручную редактировать и знать в каком месте какие группы значений находятся - достаточно

Код:
ИГРОК
	ники		= cookies
	время		= 0
	ссылки		=
	пароль		= lol

СТАТИСТИКА
	убийств		= 0
	смертей		= 10

СОХРАНЕНО
	жись		= 85.000000
	бронь		= 0.000000
где, слова большими буквами это комменты. Или вовсе подойдет

Код:
ники	= cookies
время	= 0
ссылки	=
пароль	= lol
убийств	= 0
смертей	= 10
жись	= 85.000000
бронь	= 0.000000
причем, все равно будет ясно, что хранит каждый ключ.




Кстати, заметили, что INI ридер/райтер не создает файлы, если они не существуют? Это большой плюс, объясню почему: если нужен специальный формат INI файла, который еще не существует, то достаточно создать в моде строку с этим самым форматом, создать новый файл с помощью fopen и записать в открытый файл эту строку, далее файл закрыть.

Покажу на примере, как можно добиться нужного формата файлов.

Код:
// это формат файла для аккаунтов игроков
#define accountFileFormat \
"[PLAYER]\r\n\
nicks=%s\r\n\
time=%d\r\n\
links=%s\r\n\
password=%s\r\n\
\r\n\
[STATS]\r\n\
kills=%d\r\n\
deaths=%d\r\n\
\r\n\
[SAVED]\r\n\
hp=%.2f\r\n\
ap=%.2f"


public OnPlayerCommandText ( playerid, cmdtext[] )
{
	if ( strcmp( cmdtext, "/register", true, 9 ) == 0 ) // если игрок ввел в чате /register
	{
		new regName[20]; GetPlayerName( playerid, regName, 20 ); // узнаем ник игрока

		if ( fexist(regName) ) // если файл для этого ника уже существует
		{
			SendClientMessage( playerid, 0xFF00000AA, " * Этот аккаунт уже зарегистрирован! Выбери другой ник." );
			return 1;
		}

		if ( cmdtext[9] == 0 || cmdtext[10] == 0 ) // если не указан пароль
		{
			SendClientMessage( playerid, 0xFF00000AA, " * Не указан пароль! Формат: /register пароль" );
			return 1;
		}


		new File: pFile = fopen( regName, io_write ); // создадим файл с именем игрока

		if ( pFile ) // если файл создан
		{
			new playerFileContent[255]; // создадим и сформируем строку для записи со стандартными значениями файла
			format( playerFileContent, 255, accountFileFormat, "", 0, "", cmdtext[10], 0, 0, 100.0, 0.0 );

			fblockwrite( pFile, playerFileContent ); // запишем строку в файл
			fclose( pFile ); // закроем файл

			SendClientMessage( playerid, 0x00FF00AA, " * Аккаунт успешно зарегистрирован! Используй /login, чтобы войти в него." );
			return 1;
		}


		// если не удалось создать файл
		SendClientMessage( playerid, 0xFF00000AA, " * Не удалось создать файл для аккаунта! Попробуй еще раз. " );
		return 1;
	}


	return 0;
}
Теперь при регистрации будет сразу же создаваться файл аккаунта со стандартными настройками. Такой файл будет читать/писать любой INI ридер/райтер и мой тем более (: . В итоге получен нужный результат без всяких секций.
Reply
#8

всетаки несомненный плюс mysql можно увидеть в простом примере) на старом нашем сервере у нас было 1500 аккаунтов) был мод гто и там как известно вся информация о игроке хранилась в двух папочках) получалось что на 1 юзера - 2 файла) и пока выкачаешь эти файлы по фтп все проклянешь теперь же с бд у меня целых 3 таблицы для пользовательских данных, есть очень информативный веб-интерфейс (пользовательский и администраторский) и при этому резервное копирование перестало быть гемороем))) исходные коды всегда у меня) скачал дамп БД и все) а не как раньше приходилось архивировать все эти файлы на сервере и качать архивом xD
Reply
#9

Если это будет записывать быстрее, чем Dini, то буду это использовать 100%
Reply
#10

Quote:
Originally Posted by Serafim_sd
всетаки несомненный плюс mysql можно увидеть в простом примере) на старом нашем сервере у нас было 1500 аккаунтов) был мод гто и там как известно вся информация о игроке хранилась в двух папочках) получалось что на 1 юзера - 2 файла) и пока выкачаешь эти файлы по фтп все проклянешь теперь же с бд у меня целых 3 таблицы для пользовательских данных, есть очень информативный веб-интерфейс (пользовательский и администраторский) и при этому резервное копирование перестало быть гемороем))) исходные коды всегда у меня) скачал дамп БД и все) а не как раньше приходилось архивировать все эти файлы на сервере и качать архивом xD
Спору нет, что MySQL или любая другая СУБД делает чудеса, если нужно хранить кучи мелких записей одним или несколькими файлами. НО тут опять же вопрос компромиса: удобство ручного редактирования или удобство при бэкапе.

У меня к примеру ща мод все данные держит в одном файле БД sqlite (вроде бы удобство для бэкапа). Однако, чтобы сделать какие-то ручные изменения, нужно выкл серв, скачать себе по фтп этот файл, с помощью редактора файлов sqlite сделать изменения, залить обратно файл, запустить серв. На лицо удобство хранения и абсолютный напряг с ручным редактированьем, т.е. без входа на серв или других хитрожопых манипуляций через ркон и скриптинг, данные вручную не изменить.

C MySQL немного проще ( для меня (: ) - нужно установить себе редактор БД MySQL, конектится к серву БД, и там уже менять данные вручную. НО это для тех кто знаком с этими базами данных. Я не сомневаюсь, что многим эти базы данные незнакомы и вощем-то не нужны, чтобы не напрягать голову лишним. Именно для обычных скриптеров и существуют разные библиотеки для чтения/записи данных в файлах. Их достаточно легко понять и можно уже сразу использовать, не заботясь об установке и администрировании сложных для понимния MySQL серверов.


Как грится я прошел через все эти варианты хранения данных и ОПЯТЬ ЖЕ вернулся к INI файлам. Чесслово, мне не страшен ночной бекап даже 10000 мини файлов по фтп, т.к. бэкап каждый день я не делаю. Каждый день делается бэкап всего VPS или всего выделенного серва к примеру, и если нужно можно данные восстановить.

Мой выбор почему-то опять лег на INI файлы.


Quote:
Originally Posted by Alone_MAF1A
Если это будет записывать быстрее, чем Dini, то буду это использовать 100%
обязательно при готовой версии скрипта выложу тесты Dini, SII и mxINI. Кто не знал, что есть еще и SII - теперь знайте, однако, SII кушает много ОЗУ и автор свою работу забросил. Я просил его сделать тоже и секции для INI файлов, но увы.
Reply
#11

[off]мб холивар? xD шутко[/off]

mysql также удобна тем что можно без труда сделать прекрасную веб-статистику для сервера и выполнять любые операции через веб-интерфейс) на моем сервере например регистрация и премодерация осуществляется как раз через подобный веб-интерфейс) также там небольшой блог, в котором я выкладываю новости сервера) кстати чтобы произвести какие-то изменения достаточно чтобы просто игрока небыло на сервере) а написаный вчера скрипт сохранения транспорта вообще работает в режиме онлайн) изменил цыферку в бд - опа и новая машинка)
Reply
#12

Старайся не засирать инк ненужными функциями и не перегружать его . Примерно когда выйдет версия с записью?
Reply
#13

сёня выходной, пишу прямо ща оставшиеся инструменты.

Кста, какие, обычно, лишние функции в таких библах не нужны? просто спросил, т.к. лишнего ничего я не добавлю, но все-таки. И еще 1 противоположный вопрос - какие фуньки как раз-таки нужны обязательно?

я планирую вот такой набор инструментов для версии 1.0 библиотеки (сейчас 0.1) :

1 - для открытия файла
2 - для закрытия файла

3 - для чтения строки из ключа
4 - для чтения целого числа из ключа
5 - для чтения дробного числа из ключа

6 - для записи строки в указанный ключ
7 - для записи целого числа в указанный ключ
8 - для записи дробного числа в указанный ключ

Т.е. никаких дополнительных функций в файле не будет кроме этих 8 штук. Все описания инструментов будут лежать в самом верхнем комменте скрипта, для удобства тех, кто не желает читать код, а хочет просто пользоваться и знать что как работает. Если есть пожелания насчет других инструментов, посоветуйте. Я могу ошибаться но, возможно, кому-то пригодятся и такой дополнительный набор инструментов как:

* - проверка, существует ли INI файл по указанному пути ( аналог fexist )
* - создание INI файла с указанным контентом
* - удаление INI файла ( аналог fremove )

Повторюсь, эти * это те дополнительные инструменты, которые я добавлю, если они будут вам нужны. Если они не нужны, их не будет. ТАкже можете предложить свои поправки в базовые 8 инструментов.
Reply
#14

Проверка файла будет лишней функцией, ибо fexist есть и его хватит =)
Reply
#15

Вощем, зацените (:

См. первый пост. По результатам многочисленных тестов я могу сказать, что на операции в ОЗУ тратятся какие-то крохи в долях от миллисекунды. Самая большая трата времени идет при чтении и записи на диск (: кто бы сомневался. Причем, чтение идет раза в 3 быстрее. Обычный файл профиля игрока, может быть создан или всячески изменен в ОЗУ за максимум 1 милисекунду, зато при закрытии, запись на диск занимает 3 мсек. Еси кого не пугают такие ужасно малые цифры, можете отложить Dini на дальнюю полку.

Через пару дней добавлю тестинг (: для наглядности. Хотя чтобы уловить эти милисекунды придется, устроить настоящее испытаниее с тысячами файлов или большими файлами.
Reply
#16

А он поддерживает сохранение русского текста?
Reply
#17

мм, опробую обязательно
Reply
#18

Quote:
Originally Posted by [MiB
_J ]
А он поддерживает сохранение русского текста?
Естессна! Более того в названиях ключей и в значениях можно ставить пробелы и табуляции, поэтому вот такой пример будет абсолютно правильным:

Code:
 название моего ключа = моё значение
причем ini_getString вернет строку "моё значение", если в качестве ключа указать любое из трех имен ключа "название моего ключа", "моего ключа" или "ключа". Также по вашему выбору в файле могут быть такие метаморфозы как
Code:
a = b = c
эта вышеуказанная строка фактически содержит след. ключи и значения:
`a` = `b`
`a` = `b = c`
`a = b` = `c`
`b` = `c`

все зависит от вашего воображения по оформлению
Reply
#19

Ахренеть) Спасибо автору...

Не ожидал что так будет:
Code:
SA-MP Dedicated Server
[21:37:13] 9079419
[21:37:13] 
 `ключ_со_строкой` = `текстовое значение`,
 `ключ_с_числом` = `123456`,
 `ключ_с_дробью` = `3.141598` 

[21:37:13] 9079422
Reply
#20



Кста, нужна ли кому функция удаления ключа ?
Reply


Forum Jump:


Users browsing this thread: 4 Guest(s)