本文地址:http://m.shnenglu.com/zdhsoft/archive/2014/09/03/208216.html
本文基于cocos2dx 3.2
cocos2dx 提供了一個基于xml的用戶數(shù)據(jù)存貯類,給基于cocos2dx開發(fā)的用戶數(shù)據(jù)存貯,這個類名就是UserDefault,在cocos2dx 2.x中是CCUserDefault。我的程序用的就是這個,但是最近老出錯,于是分析源代碼,發(fā)現(xiàn)了一個讓我震驚的東西。經(jīng)過分析,發(fā)現(xiàn)用UserDefault每讀寫一次數(shù)據(jù),都會創(chuàng)建一個tinyxml對象,然后讀取xml內(nèi)容。如果是寫數(shù)據(jù),還是寫入xml一次。下面是對應(yīng)的代碼:
讀取key,所以各種讀取key的操作,都是類似這樣。
double UserDefault::getDoubleForKey(const char* pKey, double defaultValue)
{
const char* value = nullptr;
tinyxml2::XMLElement* rootNode;
tinyxml2::XMLDocument* doc;
tinyxml2::XMLElement* node;
node = getXMLNodeForKey(pKey, &rootNode, &doc);
// find the node
if (node && node->FirstChild())
{
value = (const char*)(node->FirstChild()->Value());
}
double ret = defaultValue;
if (value)
{
ret = utils::atof(value);
}
if (doc) delete doc;
return ret;
}
關(guān)于getXMLNodeForKey的實現(xiàn)
/**
* define the functions here because we don't want to
* export xmlNodePtr and other types in "CCUserDefault.h"
*/
static tinyxml2::XMLElement* getXMLNodeForKey(const char* pKey, tinyxml2::XMLElement** rootNode, tinyxml2::XMLDocument **doc)
{
tinyxml2::XMLElement* curNode = nullptr;
// check the key value
if (! pKey)
{
return nullptr;
}
do
{
tinyxml2::XMLDocument* xmlDoc = new tinyxml2::XMLDocument();
*doc = xmlDoc;
std::string xmlBuffer = FileUtils::getInstance()->getStringFromFile(UserDefault::getInstance()->getXMLFilePath());
if (xmlBuffer.empty())
{
CCLOG("can not read xml file");
break;
}
xmlDoc->Parse(xmlBuffer.c_str(), xmlBuffer.size());
// get root node
*rootNode = xmlDoc->RootElement();
if (nullptr == *rootNode)
{
CCLOG("read root node error");
break;
}
// find the node
curNode = (*rootNode)->FirstChildElement();
while (nullptr != curNode)
{
const char* nodeName = curNode->Value();
if (!strcmp(nodeName, pKey))
{
break;
}
curNode = curNode->NextSiblingElement();
}
} while (0);
return curNode;
}
關(guān)于setValueForKey的實現(xiàn)
static void setValueForKey(const char* pKey, const char* pValue)
{
tinyxml2::XMLElement* rootNode;
tinyxml2::XMLDocument* doc;
tinyxml2::XMLElement* node;
// check the params
if (! pKey || ! pValue)
{
return;
}
// find the node
node = getXMLNodeForKey(pKey, &rootNode, &doc);
// if node exist, change the content
if (node)
{
if (node->FirstChild())
{
node->FirstChild()->SetValue(pValue);
}
else
{
tinyxml2::XMLText* content = doc->NewText(pValue);
node->LinkEndChild(content);
}
}
else
{
if (rootNode)
{
tinyxml2::XMLElement* tmpNode = doc->NewElement(pKey);//new tinyxml2::XMLElement(pKey);
rootNode->LinkEndChild(tmpNode);
tinyxml2::XMLText* content = doc->NewText(pValue);//new tinyxml2::XMLText(pValue);
tmpNode->LinkEndChild(content);
}
}
// save file and free doc
if (doc)
{
doc->SaveFile(UserDefault::getInstance()->getXMLFilePath().c_str());
delete doc;
}
}
它的flush方法也有驚人的發(fā)現(xiàn):
void UserDefault::flush()
{
}
它是一個空函數(shù),也就是說,你在寫入數(shù)據(jù)的時候,會以為最后會通過flush才會寫入數(shù)據(jù),沒想全錯了!
如果你用它存貯比較多的字段時,你就會現(xiàn),你悲劇了。
幸好發(fā)現(xiàn)及時,這里不建議大家使用UserDefault做為你的數(shù)據(jù)存貯。
可以可以用自定義的方式文件讀寫
如可以通過標準的C讀寫 fopen,fwrite等或iostream也都可以,重點是讀寫的文件路徑,會有所不同,下面是得到文件路徑的例子
std::string strFullFileName = FileUtils::getInstance()->getWritablePath() + DATA_FILE_NAME;
最后:不要求寫太高質(zhì)量的代碼,但也不要寫的太低質(zhì)量了