/*
;~ 函数用于保存读写 任意维度 键值对类型 的 对象数据 (字典 / 数组 , 不包括 复杂类和对象)

file_write_dict(dict, file, writeStartPos := 6)
  ;~ 参1 dict :			对象字典
  ;~ 参2 file :			要保存字典 的 文件路径
  ;~ 参3 writeStartPos :	写入文件起始位置, 在win7系统中似乎写入字节有bom存在, 故建议在起始6字节后写入字节

file_read_dict(file, readStartPos := 6)
  ;~ 参1 file : 			读取字典 的 文件路径
  ;~ 参2 readStartPos :  	原理同上函数参3

*/


;~ 示例1, 保存简单字典
dict1 := {"abc": ""
    , "bbb": 555
    , "ccc": "岁月如梭啊"}

;~ 写入字典
file_write_dict(dict1, A_ScriptDir "\dict1.dict")

;~ 读出字典
obj := file_read_dict(A_ScriptDir "\dict1.dict")
a := ""
for key, var in obj
  a .= key "=" var "`n"
MsgBox, % a


;~ 示例2, 保存多维字典

dict2 := {"abc": [123, 661]
    , "bbb": ["bbbb1346sdfhzdf", "abcd`n可以嘛"]
    , "ccc": ["0x123", 0x6498]}

;~ 写入字典
file_write_dict(dict2, A_ScriptDir "\dict2.dict")
;~ 读出字典
obj := file_read_dict(A_ScriptDir "\dict2.dict")

a := ""
for key, var in obj
  a .= key "=" var[1] "-" var[2] "`n"
MsgBox, % a
return

;------------------------------------------
;~ 读取文件字典
file_read_dict(file, readStartPos := 6) {
  static dataMinLen := 128 * 1024
  local obj, dataLen, dictLen, keylen, key, pos, buff

  ret := {}
  VarSetCapacity(buff, dataMinLen, 0)

  ;~ 打开文件, 取数据总长
  obj := FileOpen(file, "r")

  ;~ 读取尺寸信息
  obj.RawRead(buff, readStartPos + 8)

  ;~ 数据总长
  dataLen := NumGet(buff, readStartPos		, "UInt")

  ;~ 字典总长
  dictLen := NumGet(buff, readStartPos + 4	, "UInt")

  ;~ 具体数据起始端
  pos := readStartPos + 8

  ;~ 若空间不足, 则拓宽
  if (dataLen > dataMinLen)
    VarSetCapacity(buff, dataLen, 0)

  ;~ 读取所有数据 后 关闭文件
  obj.pos := 0
  obj.RawRead(buff, datalen)

  obj.close()
  obj := ""

  ;~ 读取键值
  loop %dictLen% {
    ;~ 取键名
    keylen := NumGet(buff, pos, "UInt")
    pos += 4
    key := StrGet(&buff + pos, keylen)
    pos += keylen

    ;~ 取值
    ret[key] := file_read_dict_sub(buff, pos)
  }

  ;~ 释放内存
  VarSetCapacity(buff, 0, 0)
  buff := ""

  return ret
}	;~ file_read_dict() 函数尾

;~ 读取文件字典 子函数, 递归函数
file_read_dict_sub(byref buff, byref pos) {
  static TYPE_STRING	:= 0
  static TYPE_DICT	:= 1

  varType := NumGet(buff, pos, "UChar")
  pos += 1

  ;~ 为字符串时
  if (varType = TYPE_STRING) {
    ret := ""
    ;~ len 此处为字符串数据长度
    len := NumGet(buff, pos, "UInt")
    pos += 4
    ret := (len = 0) ? "" : StrGet(&buff + pos, len)
    pos += len

  ;~ 为字典时
  } else if (varType = TYPE_DICT) {
    ret := {}
    ;~ len 此处为 字典键值对数量
    len := NumGet(buff, pos, "UInt")
    pos += 4
    Loop %len% {
      ;~ len 此处为键长
      len := NumGet(buff, pos, "UInt")
      pos += 4
      key := StrGet(&buff + pos, keylen)
      pos += len
      ret[key] := file_read_dict_sub(buff, pos)
    }
  }
  return ret
}	;~ file_read_dict_sub() 函数尾

;------------------------------------------
;~ 写入字典到文件
file_write_dict(dict, file, writeStartPos := 6) {
  static dataMinLen := 128 * 1024
  local buff, buffLen, key, var, pos, obj

  ;~ 若传入首位参数非字典, 直接返回0
  if not IsObject(dict)
    return 0

  buffLen := dataMinLen

  VarSetCapacity(buff, buffLen, 0)

  ;~ 预留 4 byte 放置数据总长
  pos := writeStartPos + 4

  ;~ 前两个数据为 整体数据长度, 键值对 数量, 无符号整形
  numput(dict.count(), buff, pos, "UInt")
  pos += 4

  for key, var in dict
  {
    ;~ 1. 写入键:
      ;~ 1.1 键长		UInt 	4Byte
      ;~ 1.2 键内容	String	...
    file_write_dict_str(key, buff, buffLen, pos)

    ;~ 2. 写入值:
      ;~ 2.1 值类型 	UChar	1Byte		0>字符串 1>对象
      ;~ 2.2 写入长度	UInt	4Byte
        ;~ 2.2.1. 为 字符串	时, 写入 值长度
        ;~ 2.2.2. 为 字典	时, 写入 键值对数量
      ;~ 2.3 写入内容 ...
    file_write_dict_obj(var, buff, buffLen, pos)

  }

  ;~ 将数据 总长 写入起始位置 writeStartPos
  NumPut(pos, buff, writeStartPos, "UInt")


  ;~ 将 缓存变量写入文件
  obj := FileOpen(file, "w")
  obj.RawWrite(buff, pos)
  obj.close()
  obj := ""

  ;~ 释放内存
  VarSetCapacity(buff, 0, 0)
  buff := ""

  ;~ 返回写入总长
  return pos
}	;~ file_write_dict() 函数尾

;~ 写入字典到文件 子函数, 写入字符串
file_write_dict_str(str, byref buff, byref buffLen, byref pos) {

  static dataMinLen := 128 * 1024
  local len, finalLen, ls, i, v

  ;~ 求所需字符串长度
  len := (str = "") ? 0 : StrPut(str) * 2

  ;~ 剩余总长: 起始点 + 长度量整形 + 数据总长
  finalLen := pos + 4 + len

  ;~ 最终长度若不足, 则增加长度
  if (finalLen > buffLen) {

    ;~ 读出所有字节
    ls := []
    Loop, % buffLen
      ls.push(NumGet(buff, A_Index - 1, "UChar"))

    ;~ 最终尺寸 + 1024 * 128
    buffLen := finalLen + dataMinLen

    ;~ 重置缓存区尺寸
    VarSetCapacity(buff, buffLen, 0)

    ;~ 重新写入数据
    for i, v in ls
      NumPut(v, buff, i - 1, "UChar")

    ls := ""
  }

  ;~ 写入字符串长度
  NumPut(len, buff, pos, "Uint")
  pos += 4

  ;~ 若字符串不为空, 写入字符串
  if (str <> "") {
    StrPut(str, &buff + pos, len)
    pos += len
  }
}	;~ file_write_dict_str() 函数尾

;~ 写入字典到文件 子函数, 写入字符串 或 字典
file_write_dict_obj(obj, byref buff, byref buffLen, byref pos) {

  static dataMinLen := 128 * 1024
  static TYPE_STRING	:= 0
  static TYPE_DICT	:= 1

  ;~ 若剩余尺寸不足5位(不足存放类型和长度), 拓宽 缓存变量
  if (buffLen - pos <= 5) {

    ;~ 读出所有字节
    ls := []
    Loop, % buffLen
      ls.push(NumGet(buff, A_Index - 1, "UChar"))

    ;~ 最终尺寸 + 1024 * 128
    buffLen += dataMinLen

    ;~ 重置缓存区尺寸
    VarSetCapacity(buff, buffLen, 0)

    ;~ 重新写入数据
    for key, var in ls
      NumPut(var, buff, i - 1, "UChar")

    ls := ""
  }

  if not IsObject(obj) {
    ;~ 写入 类型
    NumPut(TYPE_STRING, buff, pos, "UChar")
    pos += 1

    file_write_dict_str(obj, buff, buffLen, pos)

  } else {
    ;~ 写入 类型
    NumPut(TYPE_DICT, buff, pos, "UChar")
    pos += 1

    ;~ 字典 长度
    NumPut(obj.count(), buff, pos, "UInt")
    pos += 4

    for key, var in obj {
      ;~ 写入键
      file_write_dict_str(key, buff, buffLen, pos)
      ;~ 写入值
      file_write_dict_obj(var, buff, buffLen, pos)
    }
  }
}	;~ file_write_dict_obj() 函数尾

 

声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。