场景:
1. 在Mac下Cocoa开发,可以使用NSUserDefaults很容易的存储配置信息,而且它还支持基本类型的NSDictionary,NSArray等复杂类型. 我们使用这个类来存储运行时配置,
比如多语言选项, 检查更新选项, 快捷键设置等等.这个信息自动存储在bundleid的相关位置.
参考: http://blog.csdn.net/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
#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;
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" }
参考:
https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/index.html