Тема: AHK: Обсуждение Ini file object
Тема Ini file object.
Win10x64 AhkSpy, Hotkey, ClockGui
Вы не вошли. Пожалуйста, войдите или зарегистрируйтесь.
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться
Тема Ini file object.
Через FileMapping интереснее было бы.
А что это даёт?
Хорошая идея. Однако я считаю было бы удобнее если все содержимое ини файла считывалось в массив (где ключи это имена разделов) и соответственно из таблицы обратно записывало в ини файл командой.
Может кто из вас поведает, что за FileMapping.
Я не пользовался, но, насколько понимаю, это используется в основном для обмена данными между процессами.
Двое проголосовали за то что это полезно в данном контексте...
Вот здесь написано: http://vsokovikov.narod.ru/New_MSDN_API … fl_map.htm. Это просто ради интереса, можно перезаписывать как обычно.
Бегло просмотрел, очень кстати доходчиво написано, спасибо. Вы можете сказать как это можно применить в данной теме?
очень кстати доходчиво написано
Ну так это дословный перевод этой статьи.
Вот здесь пример есть: https://www.autohotkey.com/boards/viewt … ileMapping.
Я вас понял, теперь поймите меня, типа нет желания погружаться в тему, но есть желание понять какие принципы данного метода и как могут тут использоваться.
Это когда не хочется ходить по ссылкам, а тебе просто товарищи говорят - что вот есть такая штука, я про неё то-то то-то знаю, и её вот так вот тут можно применить. Или у нас тут так не принято?
Да понятно, что не просто. Просто, если ini файл окажется этак так на гигабайт 30, то с его чтением и записью будет сложно.
Ок, я же не говорю что даже такое не может быть.
В чём принцип?
Мы меняем только нужные регистры памяти, а остальное сдвигаем?
Пусть как было так и остается, мало у кого ini файл будет в 30 гб.
А как было то?
Как в справке, через FileOpen.
А где там FileMapping.
Двое проголосовали за то что это полезно в данном контексте...
А где было голосование?
Просто, если ini файл окажется этак так на гигабайт 30, то с его чтением и записью будет сложно.
А вы уверены, что через FileMapping будет быстрее?
Тесты проводили?
Пусть как было так и остается
Вы сабж имели в виду.
А где было голосование?
Образно выразился: svoboden предложил, belyankin12 поддержал, против никого не было.
А вот до сих пор интересно - FileMapping это нечто очень запутанно-сложное, и простыми словами нельзя объяснить его принцип действия в данном контексте.
Не-не-не, я не о FileMapping говорил. Я говорил о улучшении концепции исполнения идеи. Чтобы весь ини файл записывался в массив при чтении, а во время работы, скрипт уже работал с массивом, добавляя, меняя и т.д. После чего массив с помощью функции записывался в ини файл. Что-то типо такого:
; Ini file:
;[Tag1]
;Key1=123
;Key2=456
;[Tag2]
;Key1=abc
;Key2=dfe
;
arr := iniread(path) ; arr := {Tag1: {Key1: 123, Key2: 456}, Tag2: {Key1: "abc", Key2: "dfe"}}
arr["Tag2"]["Key2"] := "fff"
arr["Tag3"]["Key1"] := "new"
iniwrite(arr)
; New ini file:
;[Tag1]
;Key1=123
;Key2=456
;[Tag2]
;Key1=abc
;Key2=fff
;[Tag3]
;Key1=new
;
То есть не использовать все эти функции а напрямую работать с массивом.
Практически так и есть, массив this.Data. Вы можете легко переделать этот простейший мой пример под себя. Но в чём удобство?
Метод Read добавляет опцию Default.
Метод Write создаёт массив если секция не существует.
CheckChanged не будет переписывать файл без необходимости, так как распространена ситуация, когда программа запускается с чтением настроек, и закрывается без внесения новых.
Все, что вы перечислили имеет право на жизнь. Мои предпочтения скорее дело вкуса было, чем что-то очень необходимое к реализации. Просто я подумал, что мое виденье придется вам по душе. Однако я бы все равно сделал возможность записывать произвольный массив в ini файл хотя бы для того, чтобы можно было держать прямо в коде все стандартные настройки.
Если сделать так
Ini := new IniFile(A_ScriptDir "\Settings.Ini")
Ini.changed := 1
Arr := Ini.Data
то можно далее пользоваться как обычным массивом, с возможностью записи, или сделать Clone для чтения первоначальных настроек. Как видите это просто и стандартно, но не особо вписывается в обычную концепцию работы с ини файлом, поэтому не вижу смысла делать это опциями в публичной версии.
чтобы можно было держать прямо в коде все стандартные настройки.
Для этого используется Default в Read. И это намного проще и удобнее, чем прописывать какие то условия для записи или не записи стандартных настроек в файл, и ещё держать все стандартные настройки в "стороне" от методов чтения.
Тесты проводили?
Не.
А чего тогда пишите, что так интереснее было бы?
Может овчинка выделки не стоит.
В общем обсуждение получилось на редкость конструктивным.
Без тестирования при конкретных условиях никакой конкретики быть не может.
Вот, например, тут человек провел тесты с одними результатами:
https://lemire.me/blog/2012/06/26/which … m-or-mmap/
Вот тут другие результаты:
https://groups.google.com/forum/#!topic … ULzTNlgkNo
Я пока в танке, давай так
это соединение содержания файла с частью виртуального адресного пространства процесса
В смысле весь файл будет загружен в часть оперативной памяти процесса, или можно загрузить туда нужную часть файла.
Так а чем тогда IniWrite не устраивает?
Как я понимаю, можно и нужную часть и целый файл.
Просто с помощью FileMapping мы минуем копирование из кеша в буфер нашей программы, так как напрямую обращаемся к кешу с помощью его отображения в адресном пространстве нашей программы.
Блин, кто к кому обращается?
Наша программа к кешу.
Если тебя это заинтересовало, тут все расписано:
https://habr.com/ru/company/smart_soft/blog/228937/
Не, это сложно. RawRead что, грузит данные сначала в кеш, а потом уже выгружает в память процесса?
все стандартные операции файлового ввода / вывода работают через страничный кэш
В общем сложно, ничего не получится.
Блин, кто к кому обращается?
Наша программа к кешу.
Это я про два поста выше, не понятно кто с кем разговаривал.
Видимо svoboden интересуется, чем тебя не устраивает IniWrite.
svoboden, в теме с кодом этого скрипта всё же написано.
Кстати, если секция одна, то так можно вписывать сразу несколько значений:
DllCall("WritePrivateProfileSection", "str", "Section", "str", "key1=val1`nkey2=val2`n", "str", A_ScriptDir "\test.ini")
loop 2
{
IniRead, OutputVar, % A_ScriptDir "\test.ini", Section, key%A_Index%
msgbox % OutputVar
}
А winapi зачем? IniWrite так же можно использовать. Но так вся секция переписывается, что не всегда удобно.
Точно, а я и не заметил, что там пары можно использовать (если честно - никогда этими функциями не пользовался).
Ну тогда, класс serzh82saratov целесообразно использовать только при более чем 1 секции.
Ну почему, если в процессе работы скрипта изменения в ini предполагается вносить часто, то писать не сразу в файл, а сперва в объект, а потом один раз в файл, — такая идея имеет право на жизнь.
Так если у нас только одна секция, то за один раз это можно сделать с помощью iniwrite.
Кстати, понял почему я не знал про пары - в русской справке про них ни слова.
за один раз это можно сделать с помощью iniwrite
Не всегда известно, что текущее изменение будет последним.
Тогда можно для ini с одной секцией избавиться от парсинга регулярными выражениями.
Баг:
Ini := new IniFile(A_ScriptDir "\Settings.Ini")
Ini.Write("MySection", "MyKey1", " a ")
MsgBox % """" Ini.Read("MySection", "MyKey1") """"
Ini.Save()
Ini := new IniFile(A_ScriptDir "\Settings.Ini")
MsgBox % """" Ini.Read("MySection", "MyKey1") """"
Баг:
Поправил.
Почитал ещё раз, так и не пойму что даёт страничный кеш в данной задаче.
Файл всё равно надо загрузить весь в ОП.
Плюс только в том что при закрытии программы файл вероятнее всего останется в кеше, и его не надо будет загружать снова?
Но если оперативки 8 гигов, а как тут говорилось файл будет в 9 гигов, то его всё равно весь не загрузишь, придётся периодически ждать жёсткий диск.
У меня в примере такой файл конечно мы и прочитать то не сможем, но можно сделать чтение порциями. И хоть так, хоть по другому, всё равно не хватит памяти создать массив секций с ключами.
Тогда можно для ini с одной секцией избавиться от парсинга регулярными выражениями.
А как создать массив без regex?
А, кажется понял тебя - GetPrivateProfileSectionNames и GetPrivateProfileSection, тогда причём тут одна секция?
Я про Unicode только не понял в справке по IniRead.
Unicode: IniRead and IniWrite rely on the external functions GetPrivateProfileString¬ and WritePrivateProfileString¬ to read and write values. These functions support Unicode only in UTF-16 files; all other files are assumed to use the system's default ANSI code page.
Filename := A_ScriptDir "\Settings.Ini"
IniRead, OutputVarSectionNames, % Filename
MsgBox % OutputVarSectionNames
Loop, Parse, OutputVarSectionNames, `n, `r
{
IniRead, OutputVarSection, % Filename, % A_LoopField
MsgBox, , % A_LoopField, % OutputVarSection
}
https://www.autohotkey.com/boards/viewt … mp;t=38511
Получается или преобразовать файл в UTF-16, сделав его размер раза в полтора - два больше, или перекодировать все данные. Не поймёшь что правильнее и надёжнее.
Вот, если перекодировать.
Но GetPrivateProfileSection режет пробелы, и это уже нельзя реализовать.
Ini := new IniFile(A_ScriptDir "\Settings.Ini")
Ini.Write("MySection", "MyKey1", " a ")
MsgBox % """" Ini.Read("MySection", "MyKey1") """"
Ini.Save()
Ini := new IniFile(A_ScriptDir "\Settings.Ini")
MsgBox % """" Ini.Read("MySection", "MyKey1") """"
Также в планах было оставлять комментарии, а их GetPrivateProfile не прочитает.
Class IniFile {
__New(File, FileBackUp = "") {
this.Path := File
this.FileBackUp := FileBackUp
IniRead, SectionNames, % File
Loop, Parse, SectionNames, `n, `r
{
this.Data[SectionName := this._StrUtf8BytesToText(A_LoopField)] := {}
IniRead, Section, % File, % A_LoopField
Loop, Parse, % this._StrUtf8BytesToText(Section), `n, `r
{
i := InStr(A_LoopField, "=")
this.Data[SectionName, SubStr(A_LoopField, 1, i - 1)] := SubStr(A_LoopField, i + 1)
}
}
}
Read(Section, Key, Default = "") {
If (Default != "" && !this.Data[Section].HasKey(Key))
Return Default
Return this.Data[Section][Key]
}
Write(Section, Key, Value = "") {
If !IsObject(this.Data[Section])
this.Data[Section] := {}
this._CheckChanged()
Return this.Data[Section][Key] := Value
}
Delete(Section, Key) {
this._CheckChanged()
Return this.Data[Section].Delete(Key)
}
DeleteSection(Section) {
this._CheckChanged()
Return this.Data.Delete(Section)
}
_CheckChanged() {
If !this.changed
this.changed := 1
}
Save() {
If !this.changed
Return
For Section, Keys in this.Data
{
Str .= "[" Section "]`n"
For Key, Value in Keys
Str .= Key "=" Value "`n"
}
If this.FileBackUp
FileCopy, % this.Path, % this.FileBackUp, 1
oFile := FileOpen(this.Path, "w", "UTF-8")
oFile.Length := 0
oFile.Write(Str)
oFile.Close()
}
_StrUtf8BytesToText(vUtf8) ; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=38511
{
if A_IsUnicode
{
VarSetCapacity(vUtf8X, StrPut(vUtf8, "CP0"))
StrPut(vUtf8, &vUtf8X, "CP0")
return StrGet(&vUtf8X, "UTF-8")
}
else
return StrGet(&vUtf8, "UTF-8")
}
}
тогда причём тут одна секция?
Для прочтения каждой секции нужно каждый раз обращаться к файлу - а ты ж как-раз этого хотел избежать.
что даёт страничный кеш в данной задаче
Не совсем тебя понял. У тебя и так всё кешируется, так как не указан флаг FILE_FLAG_NO_BUFFERING.
Для прочтения каждой секции нужно каждый раз обращаться к файлу - а ты ж как-раз этого хотел избежать.
А, ну да. Значит GetPrivateProfile больше рассматриваем.
У тебя и так всё кешируется, так как не указан флаг FILE_FLAG_NO_BUFFERING
О как, то есть FileOpen сначала копирует весь файл в кеш? И есть смысл этого избегать?
Не знаю, надо проверять.
То есть я имею в виду - замерить скорость работы с базой данных на сетевом файле:
1) используя страничный кеш (как сейчас)
2) через filemapping
3) через filemapping + используя кеш хинты (FILE_FLAG_RANDOM_ACCESS, FILE_FLAG_SEQUENTIAL_SCAN, FILE_FLAG_WRITE_THROUGH, FILE_ATTRIBUTE_TEMPORARY)
4) через filemapping + FILE_FLAG_NO_BUFFERING
Почему именно на сетевом?
Думаю, что на несетевом в 99.99% это всё не будет иметь смысла - например, у меня txt файл 500mb открывается через fileread за 0.7 секунд.
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться