看了quick-cocos2d-x 的framework,发现里面有一个GameState,查了下,是数据存储的类,于是稍稍总结下我用到过的数据存储方式吧。
一共是三种方法:
- cc.UserDefault
- cc.utils.State
- io
优缺点:
前两个使用起来更方便,因为是系统已经定义好的了。但缺点是不能在lua层面随便更改文件名和路径。
所以在使用时,根据不同的需求,可选择第一或者第三,第二个不太建议使用,太麻烦了。
普通的应用信息,比如各种开关,使用cc.UserDefault保存,可随应用的删除,自动删除文件。
用户的账号信息,使用io存储,保存在sd卡中,这样用户在重装应用后,依然能顺利进入。
第一种是使用cc.UserDefault类。这是系统提供的,产生的文件名为 UserDefault.xml, 文件名在lua层面是无法修改的,如果想修改,需要修改C++代码。
两个方法,存 和 读取, 主要注意的是 不同的数据类型 调用的方法不同,如下面的例子
1 local ParamType =
2 {
3 Integer = "int",
4 String = "string",
5 Float = "float",
6 Bool = "bool",
7 Double = "double",
8 }
9
10 -- 保存
11 function NativeData:saveValeForKey(val, key, type)
12 if type == ParamType.String then
13 cc.UserDefault:getInstance():setStringForKey(key, val)
14 elseif type == ParamType.Integer then
15 cc.UserDefault:getInstance():setIntegerForKey(key, val)
16 elseif type == ParamType.Float then
17 cc.UserDefault:getInstance():setFloatForKey(key, val)
18 elseif type == ParamType.Double then
19 cc.UserDefault:getInstance():setDoubleForKey(key, val)
20 elseif type == ParamType.Bool then
21 cc.UserDefault:getInstance():setBoolForKey(key, val)
22 end
23 end
24
25 -- 读取
26 function NativeData:getValeForKey( key, type, default)
27 local vale = nil
28 if type == ParamType.String then
29 vale = cc.UserDefault:getInstance():getStringForKey(key, default)
30 elseif type == ParamType.Integer then
31 vale = cc.UserDefault:getInstance():getIntegerForKey(key, default)
32 elseif type == ParamType.Float then
33 vale = cc.UserDefault:getInstance():getFloatForKey(key, default)
34 elseif type == ParamType.Double then
35 vale = cc.UserDefault:getInstance():getDoubleForKey(key, default)
36 elseif type == ParamType.Bool then
37 vale = cc.UserDefault:getInstance():getBoolForKey(key, default)
38 end
39
40 return vale
41
42 end
第二种是使用cc.utils.State类。文件位置在framework/cc/utils/GameState.lua。默认framework并没有加载,如果我们要用到,需要手动加载。一般在myApp开头加载。
1 require("framework.cc.utils.GameState")
加载完成后,需要初始化,cc.utils.State.init(eventListener_, stateFilename_, secretKey_)
在场景初始化之前调用一次即可,如在MyApp.lua的MyApp:ctor()中调用。
eventListener_是载入或保存时的回调函数
stateFilename_是保存的文件名,如果留空或非字符串(string)则是默认的state.txt,该文件会被保存到device.writablePath下
secretKey_是 校验文件时所用到的密钥,GameState保存的数据格式为{h = hash, s = s},s是我们要保存的数据(一个table),h则是要校验的一个md5码。如果secretKey_留空或为非字符串(string)则不加校验码, 直接保存数据,跟CCUserDefault一样了。
加载完成后,就是正常的使用。load 和save 方法都会 回调 init中的第一个参数。
1 -- 这个方法一般只需调用一次,将本地文件load到内存中
2 function GameState.load()
3 end
4
5 -- newValues是新的值,其实就是加载到内存中后保存的对象么。
6 function GameState.save(newValues)
7 end
8
9 -- 返回完整路径
10 function GameState.getGameStatePath()
11 end
关于eventListener_,可以看一下 写的,很详细。
第三种是使用io 直接读写文件。这个最灵活。可以根据自己的需要设定存储目录,文件名,是否需要加密。需要注意读取之前需要判断是否存在目录 不存在则要创建。
一个简单的文件工具类
module("MakeFileUtils", package.seeall)
local lfs, os, io = require"lfs", os, io
function readFile(path)
local file = assert(io.open(path, "rb"))
if file then
local content = file:read("*all")
io.close(file)
return content
end
return nil
end
function writeFile(filename, data, rt)
local f = assert(io.open(filename, rt))
f:write(data)
f:close()
end
function checkDirOK( path )
local prepath = lfs.currentdir()
if lfs.chdir(path) then
lfs.chdir(prepath)
return true
end
if lfs.mkdir(path) then
return true
end
end
-- 读取
if not io.exists(fn) then
return
end
local cnt = MakeFileUtils.readFile(fn)
if cnt ~= nil and cnt ~= "" then
return json.decode(cnt)
end
-- 写入
1 MakeFileUtils.writeFile(fn, json.encode(cnt), "w+")