Loading
0

[库]EasyINI河许人加强版,最好用、快速的ini读写库

作者:Verdlin

翻译:河许人

我对这个库的讨论和留言进行了整合,翻译过程肯定有些瑕疵,请多包涵!谢谢!

ini文件操作是中大型程序几乎必备的操作,但是AHK自带的ini操作太low,所有其他Ini库(包括旧版本的EasyIni)语法又太麻烦。这个类的重点是使读写ini文件尽可能容易;此外,我想让这个类本身易于阅读和其他开发人员的访问。

这个类的一个意想不到的积极结果是它的执行速度比写操作要快得多。我在下面发布了一个示例,在这里,easyini类的速度比IniWrite快1162%。

您可以轻松地使用easyini对象与ini进行交互。由于自定义对象,该类允许您使用熟悉的、本机的、对象语法。

 

这个类的限制:

  • 在段名中不能使用换行符。
  • 对于任何字母数字段,(例如:“[A]”)只有一种情况是允许的。因此,如果您试图添加“[a]”“AddSection”()函数将失效。在我的1500个段示例中演示。
  • 在我的测试中,我注意到SOH(chr(1))和空格(chr(32))被写入了相同SOH。我不知道为什么会这样,但我不认为这对大多数人来说是一个问题。
  • 我还注意到,相当多的奇怪字符值被分组到相同的部分中。这对任何人来说不是一个问题。这个类只是一个奇特的自定义对象。如果在某些方面有某些问题,这可能是AHK本身的问题,而不是类的问题。
  • 您不能从文本开始,您不能有一个段落或键。我无法想象这是一个大问题。
    “=”在键名中不支持。

关于ini数据的几条注释:

  • 没有值的键可以使用
  • 尽管不推荐使用您的其他应用程序来访问相同的ini,但是“]”在段名称中是支持的。
  •  EasyIni在一个自定义对象中存储ini数据。这一定制对象的许多功劳都是Rbrtryn和Lexikos的工作,有关更多信息,请参见OrderedArray(日后会在网站分享)。由于有了OrderedArray的前期工作,我顺利完成了这个对象,使我能够维护ini文件的格式。如果在您的文件中删除了任何注释或新行,或者由于使用class_easyini而在您的文件中重新排序了任何部分或键,那么这是一个错误,请联系我!

这个库的重写也提高了整体的速度。实际上,Save()函数现在比旧的EasyIni类快了3629%!

示例:

下面是一个测试,我将所有可能的字符值(从chr())中返回给一个ini。

写入内存的时间为1秒。

写入文件需要花费17秒(比旧类快3629%)。我测试没有那么快,应该是我的电脑性能的问题!

[/crayon]

}

这个测试显示了class_easyini的哪些字符是可读的。正如我之前提到的,某些奇怪的字符被组合到相同的部分中。如果您想了解更多,请先运行前面的示例,然后运行这个示例。

[/crayon]

}

添加1500个段,键和值将会花费小于1秒的时间来写入内存和一个ini。这个例子展示了区段和键是如何区分大小写的。它会给section a-z生成错误,因为a-z已经存在于ini中。

[/crayon]

}

创建一个ini,添加和修改段、键和值,并保存。

[/crayon]

}

从字符串中加载一个ini,并在一个文件中维护所有格式(包括注释和换行)

[/crayon]

}

IniWrite vs EasyIni:

[/crayon]

}

 

Easyini类本体:

 

[/crayon]

/*
Current design (not fully implemented):
---------------------------------------------------------------------------------------------------------------------------------------------------
Comments at the top of the section apply to the file as a whole. They are keyed off an internal section called "EasyIni_ReservedFor_TopComments."
Comments above section headers apply to the the last key of the previous section.
If a comment appears between two keys, then it will apply to the key above it -- this is consistent with the solution for comments above section headers.
Newlines will be stored in similar fashion to comments.
---------------------------------------------------------------------------------------------------------------------------------------------------

[/crayon]

*/

[/crayon]

}

; For all of the EasyIni_* functions below, much credit is due to Lexikos and Rbrtryn for their work with ordered arrays
; See http://www.autohotkey.com/board/topic/61792-ahk-l-for-loop-in-order-of-key-value-pair-creation/?p=389662 for Lexikos's initial work with ordered arrays
; See http://www.autohotkey.com/board/topic/94043-ordered-array/#entry592333 for Rbrtryn's OrderedArray lib
EasyIni_CreateBaseObj(parms*)
{
; Define prototype object for ordered arrays:
static base := {__Set: "EasyIni_Set", _NewEnum: "EasyIni_NewEnum", Remove: "EasyIni_Remove", Insert: "EasyIni_Insert", InsertBefore: "EasyIni_InsertBefore"}
; Create and return new base object:
return Object("_keys", Object(), "base", base, parms*)
}

EasyIni_Set(obj, parms*)
{
; If this function is called, the key must not already exist.
; Sub-class array if necessary then add this new key to the key list, if it doesn't begin with "EasyIni_ReservedFor_"
if parms.maxindex() > 2
ObjInsert(obj, parms[1], EasyIni_CreateBaseObj())

[/crayon]

}

EasyIni_NewEnum(obj)
{
; Define prototype object for custom enumerator:
static base := Object("Next", "EasyIni_EnumNext")
; Return an enumerator wrapping our _keys array's enumerator:
return Object("obj", obj, "enum", obj._keys._NewEnum(), "base", base)
}

EasyIni_EnumNext(e, ByRef k, ByRef v="")
{
; If Enum.Next() returns a "true" value, it has stored a key and
; value in the provided variables. In this case, "i" receives the
; current index in the _keys array and "k" receives the value at
; that index, which is a key in the original object:
if r := e.enum.Next(i,k)
; We want it to appear as though the user is simply enumerating
; the key-value pairs of the original object, so store the value
; associated with this key in the second output variable:
v := e.obj[k]
return r
}

EasyIni_Remove(obj, parms)
{
r := ObjRemove(obj, parms
) ; Remove keys from main object
Removed := []
for k, v in obj._keys ; Get each index key pair
if not ObjHasKey(obj, v) ; if key is not in main object
Removed.Insert(k) ; Store that keys index to be removed later
for k, v in Removed ; For each key to be removed
ObjRemove(obj._keys, v, "") ; remove that key from key list

[/crayon]

}

EasyIni_Insert(obj, parms)
{
r := ObjInsert(obj, parms
) ; Insert keys into main object
enum := ObjNewEnum(obj) ; Can't use for-loop because it would invoke EasyIni_NewEnum
while enum[k] { ; For each key in main object
for i, kv in obj.keys ; Search for key in obj._keys
if (k = "_keys" || k = kv || SubStr(k, 1, 20) = "EasyIni_ReservedFor
" || SubStr(kv, 1, 20) = "EasyIni_ReservedFor_") ; If found...
continue 2 ; Get next key in main object
ObjInsert(obj._keys, k) ; Else insert key into obj._keys
}

[/crayon]

}

EasyIni_InsertBefore(obj, key, parms*)
{
OldKeys := obj._keys ; Save key list
obj._keys := [] ; Clear key list
for idx, k in OldKeys { ; Put the keys before key
if (k = key) ; back into key list
break
obj._keys.Insert(k)
}

[/crayon]

}

本文为原创文章,未经同意禁止转载!!