场景:
1. 在Mac下Cocoa开发,可以使用NSUserDefaults很容易的存储配置信息,而且它还支持基本类型的NSDictionary,NSArray等复杂类型. 我们使用这个类来存储运行时配置,
比如多语言选项, 检查更新选项, 快捷键设置等等.这个信息自动存储在bundleid的相关位置.
参考: http://blog.youkuaiyun.com/yepeng2014/article/details/49003753
这种配置很方面, 如果是Windows的话唯一可以和它相提并论的是注册表了, 但是注册表不容易直观的通过路径查看到, 比较麻烦.
这点Windows的SDK真的可以参考Cocoa做好点,提供方便开发人员开发常规软件的API.
2. 这里模仿了NSUserDefaults的接口写了Windows版本的,目前只能简单的存储和读取字符串类型,原始类型,对象类型的话返回void*, 这是因为C++并没有id类型.
3. 这里主要是使用了rapidjson 来作为存储格式, 相对NSUserDefaults 的XML格式稍微简单些, 因为Json读写非常快.
4. 和软件无关,可以跨产品使用.
bas_user_defaults.h:
#ifndef __BAS_USER_DEFAULTS_H
#define __BAS_USER_DEFAULTS_H
#include "bas_exp.h"
#include <Windows.h>
// 使用json来表达内容.
class LIB_BASIC BASUserDefaults
{
public:
~BASUserDefaults();
static void InitStandardUserDefaults(const wchar_t* brand,const wchar_t* product);
static BASUserDefaults* StandardUserDefaults();
static void InitUserDefaults(const char* name,const wchar_t* path);
static BASUserDefaults* GetUserDefaults(const char* name);
void SetString(const char* key,const char* value);
void SetInt(const char* key,int value);
const char* GetString(const char* key);
//1.返回rapidjson::Value对象.
void* GetValueObject(const char* key);
int GetInt(const char* key);
DWORD GetRGB(const char* key);
void WriteAll();
private:
BASUserDefaults(const char* name,const wchar_t* path);
void ReadAll();
char* name_;
wchar_t* path_;
void* document_;
};
#endif
bas_user_defaults.cpp:
#include "basic/bas_user_defaults.h"
#include <vector>
#include <string>
#include <map>
#include <iostream>
#include <stdio.h>
#include "rapidjson/document.h"
#include "rapidjson/prettywriter.h"
#include "rapidjson/filestream.h"
#include "rapidjson/stringbuffer.h"
#include "basic/bas_utility_sys.h"
static const char* gUserDefaultName = "UserDefault";
static wchar_t* gUserDefaultBrand = NULL;
static wchar_t* gUserDefaultProduct = NULL;
static std::map<std::string,BASUserDefaults*> gNameToDefault;
static rapidjson::Document* GetDocument(void* data)
{
return (rapidjson::Document*)data;
}
BASUserDefaults::~BASUserDefaults()
{
free(name_);
free(path_);
}
void BASUserDefaults::InitStandardUserDefaults(const wchar_t* brand,const wchar_t* product)
{
gUserDefaultBrand = wcsdup(brand);
gUserDefaultProduct = wcsdup(product);
wchar_t* appdata = BASUtilitySys::GetAppDataDir();
wcscat(appdata,gUserDefaultBrand);
::CreateDirectory(appdata,NULL);
wcscat(appdata,L"\\");
wcscat(appdata,gUserDefaultProduct);
::CreateDirectory(appdata,NULL);
wcscat(appdata,L"\\");
wcscat(appdata,L"Preferences.json");
InitUserDefaults(gUserDefaultName,appdata);
free(appdata);
}
void BASUserDefaults::InitUserDefaults(const char* name,const wchar_t* path)
{
gNameToDefault[name] = new BASUserDefaults(name,path);
}
void BASUserDefaults::ReadAll()
{
rapidjson::Document* document = GetDocument(document_);
FILE* file = _wfopen(path_,L"rb");
if(file)
{
fseek(file,0,SEEK_END);
long size = ftell(file);
fseek(file,0,SEEK_SET);
char* buf = (char*)malloc(size+1);
memset(buf,0,size+1);
fread(buf,size,1,file);
buf[size] = 0;
fclose(file);
if(document->Parse<0>(buf).HasParseError())
{
std::cout << "parse error" << std::endl;
document->SetObject();
}
free(buf);
}
}
void BASUserDefaults::WriteAll()
{
rapidjson::Document* document = GetDocument(document_);
FILE* file = _wfopen(path_,L"wb");
rapidjson::StringBuffer buffer;
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
document->Accept(writer);
std::string result = buffer.GetString();
fwrite((void*)result.data(),result.size(),1,file);
fclose(file);
delete document;
}
BASUserDefaults::BASUserDefaults(const char* name,const wchar_t* path)
{
name_ = strdup(name);
path_ = wcsdup(path);
rapidjson::Document* document = new rapidjson::Document();
document_ = document;
document->SetObject();
//读取路径下的json内容.
ReadAll();
}
BASUserDefaults* BASUserDefaults::GetUserDefaults(const char* name)
{
return gNameToDefault[name];
}
BASUserDefaults* BASUserDefaults::StandardUserDefaults()
{
return GetUserDefaults(gUserDefaultName);
}
void BASUserDefaults::SetString(const char* key,const char* temp_value)
{
rapidjson::Document* document = GetDocument(document_);
rapidjson::Value value(rapidjson::kStringType);
value.SetString(temp_value,strlen(temp_value),document->GetAllocator());
document->AddMember(key,value,document->GetAllocator());
}
int BASUserDefaults::GetInt(const char* key)
{
rapidjson::Document* document = GetDocument(document_);
return (*document)[key].GetInt();
}
void* BASUserDefaults::GetValueObject(const char* key)
{
rapidjson::Document* document = GetDocument(document_);
rapidjson::Value& value = (*document)[key];
return &value;
}
void BASUserDefaults::SetInt(const char* key,int temp_value)
{
rapidjson::Document* document = GetDocument(document_);
rapidjson::Value value(rapidjson::kNumberType);
value.SetInt(temp_value);
document->AddMember(key,value,document->GetAllocator());
}
const char* BASUserDefaults::GetString(const char* key)
{
rapidjson::Document* document = GetDocument(document_);
return (*document)[key].GetString();
}
DWORD BASUserDefaults::GetRGB(const char* key)
{
rapidjson::Document* document = GetDocument(document_);
const char* value = (*document)[key].GetString();
char* temp = strdup(value);
char* t = temp;
char* p = strchr(temp,',');
*p = 0;
int r = atoi(temp);
temp = p+1;
p = strchr(temp,',');
*p = 0;
int g = atoi(temp);
int b = atoi(p+1);
free(t);
return RGB(r,g,b);
}
软件启动时:
BASUserDefaults::InitStandardUserDefaults(UiUtilityProduct::GetCorporationW().c_str(),
UiUtilityProduct::GetProductAliasW().c_str());
BASUserDefaults* user = BASUserDefaults::StandardUserDefaults();
user->WriteAll();
delete user;
使用情况2: 读取随软件打包的配置文件,只读.
wchar_t* install_dir_temp = BASUtilityApp::GetProductInstallDir();
std::wstring url_path(install_dir_temp);
url_path.append(L"Option.json");
BASUserDefaults::InitUserDefaults("url",url_path.c_str());
free(install_dir_temp);
常见的配置文件:
{
"help": "http://www.xxx.com/online-help",
"purchase": "http://www.xxx.com/purchase/xxx.html",
"usupport": "http://www.xxx.com/support.html",
"color:toolbox:background":"217,250,243",
"color:toolbar:tab:font":"0,0,0"
}
参考: