[cocos2dx 3.0 (一)] 對檔案讀寫操作 +FileUtils類
一直想學習下游戲程式設計,但總是沒下定決心。現在就從Cocos2dx開始學習吧,以後也要堅持寫些經驗文章,就當是給我自己的學習歷程的一個記錄吧。
我現在下的cocos2dx版本是3.0beta2的,而網上的大多數教程都是2.x的,有些地方有些小不同,所以難免碰到點磕碰。但這些總是難免的,一下子就習慣了。
3.0沒有了CC字首,這樣看起來果真是爽多了啊
cocos2dx的檔案工具類 FileUtils,用於對檔案的簡單操作,下面列出一些大概用得到的函式:
static FileUtils* getInstance();//獲取FileUtils類的例項
cocos2dx中有很多擁有共享例項的類,再以前版本的獲取例項是用sharedXXX()函式來獲取的,而3.0都只使用一個函式getInstance()來獲取。可以看下面的說明:/** @deprecated Use getInstance() instead */ CC_DEPRECATED_ATTRIBUTE static FileUtils* sharedFileUtils() { return getInstance(); }
可以看出雖然現在還可以使用sharedFileUtils(),但他已經被標註為廢棄。很顯然使用getInstance()更加明瞭簡介。
std::string getStringFromFile(const std::string& filename);//讀取檔案中的字串
Data getDataFromFile(const std::string& filename);//獲取檔案資料
下面看一下Data類
class CC_DLL Data { public: static const Data Null; //建構函式 Data(); Data(const Data& other); Data(Data&& other); ~Data(); // 過載符號 Data& operator= (const Data& other); Data& operator= (Data&& other); unsigned char* getBytes() const;//獲取資料 ssize_t getSize() const;//尺寸 void copy(unsigned char* bytes, const ssize_t size);//從bytes複製 void fastSet(unsigned char* bytes, const ssize_t size);//從bytes快速set,使用後bytes將不能在外部使用 void clear();//清除 bool isNull() const;//判空 private: void move(Data& other); private: unsigned char* _bytes; ssize_t _size; };
unsigned char* getFileDataFromZip(const std::string& zipFilePath, const std::string& filename, ssize_t *size);//讀取壓縮檔案資料(zip格式)
如果讀取成功size中會返回檔案的大小,否則返回0。
std::string fullPathForFilename(const std::string &filename);//獲取檔案的完整路徑
如果我們通過setSearchPaths()設定搜尋路徑("/mnt/sdcard/", "internal_dir/"),然後通過setSearchResolutionsOrder()設定子區分路徑("resources-ipadhd/", "resources-ipad/", "resources-iphonehd")。如果搜尋檔名為'sprite.png' 那麼會先在檔案查詢字典中查詢key: sprite.png -> value: sprite.pvr.gz,然後搜尋檔案'sprite.pvr.gz'如下順序:
/mnt/sdcard/resources-ipadhd/sprite.pvr.gz (if not found, search next)
/mnt/sdcard/resources-ipad/sprite.pvr.gz (if not found, search next)
/mnt/sdcard/resources-iphonehd/sprite.pvr.gz (if not found, search next)
/mnt/sdcard/sprite.pvr.gz (if not found, search next)
internal_dir/resources-ipadhd/sprite.pvr.gz (if not found, search next)
internal_dir/resources-ipad/sprite.pvr.gz (if not found, search next)
internal_dir/resources-iphonehd/sprite.pvr.gz (if not found, search next)
internal_dir/sprite.pvr.gz (if not found, return "sprite.png")
如果找到返回完整路徑,沒找到返回'sprite.png'。
void loadFilenameLookupDictionaryFromFile(const std::string &filename);//從檔案匯入檔名查詢字典
檔案為plist格式如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>filenames</key>
<dict>
<key>sounds/click.wav</key>
<string>sounds/click.caf</string>
<key>sounds/endgame.wav</key>
<string>sounds/endgame.caf</string>
<key>sounds/gem-0.wav</key>
<string>sounds/gem-0.caf</string>
</dict>
<key>metadata</key>
<dict>
<key>version</key>
<integer>1</integer>
</dict>
</dict>
</plist>
key對應string
void setFilenameLookupDictionary(const ValueMap& filenameLookupDict);//從ValueMap中設定檔名查詢字典
ValueMap的定義:
typedef std::unordered_map<std::string, Value> ValueMap;
std::string fullPathFromRelativeFile(const std::string &filename, const std::string &relativeFile);//獲取相對應檔案的完整路徑
e.g. filename: hello.png, pszRelativeFile: /User/path1/path2/hello.plist Return: /User/path1/path2/hello.pvr (If there a a key(hello.png)-value(hello.pvr) in FilenameLookup dictionary. )
void setSearchResolutionsOrder(const std::vector<std::string>& searchResolutionsOrder);//設定子搜尋區分路徑
見fullPathForFilename()。
void addSearchResolutionsOrder(const std::string &order);//增加子搜尋路徑
const std::vector<std::string>& getSearchResolutionsOrder();//獲取子搜尋區分路徑
void setSearchPaths(const std::vector<std::string>& searchPaths);//設定搜尋路徑
見fullPathForFilename()。
void addSearchPath(const std::string & path);//增加搜尋路徑
const std::vector<std::string>& getSearchPaths() const;//獲取搜尋路徑
std::string getWritablePath();//獲取一個可寫入檔案的路徑
經過測試在win32平臺上,debug版本返回的是程式檔案所在的路徑,release返回的是“我的文件”路徑。
bool isFileExist(const std::string& filePath);//判斷檔案是否存在
經過測試在win32平臺上,如果路徑中包含中文字元會找不到檔案。所以可以自己寫個
bool wFileIO::isFileExist(const std::string& pFileName)
{
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32)
return CCFileUtils::getInstance()->isFileExist(pFileName);
#else
if(GetFileAttributesA(pFileName.c_str()) == INVALID_FILE_ATTRIBUTES)
return false;
return true;
#endif
}
bool isAbsolutePath(const std::string& path);判斷是否為絕對路徑
void setPopupNotify(bool notify);
bool isPopupNotify();
Sets/Gets 當檔案載入失敗時彈出messagebox.
ValueMap getValueMapFromFile(const std::string& filename);//從檔案獲取ValueMap
bool writeToFile(ValueMap& dict, const std::string& fullPath);//寫入一個ValueMap資料到plist格式檔案
ValueVector getValueVectorFromFile(const std::string& filename);//從檔案獲取ValueVector
ValueVector定義:
typedef std::vector<Value> ValueVector;
函式就這麼多了,就在這裡記錄下,到時要用再來看看
因為沒發現有直接寫檔案的函式,所以我這裡自己寫了下,雖然不知道再其他平臺會怎樣,再windows上用著再說
再win32上realse版本getWritablePath()會獲取“我的文件”,還是改成當前路徑吧
std::string wFileIO::getWritablePath()
{
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32)
return CCFileUtils::getInstance()->getWritablePath();
#else
char full_path[MAX_PATH + 1];
::GetModuleFileNameA(NULL, full_path,MAX_PATH + 1);
std::string ret((char*)full_path);
// remove xxx.exe
ret = ret.substr(0, ret.rfind("\\") + 1);
ret = convertPathFormatToUnixStyle(ret);
return ret;
#endif
}
下面是儲存檔案:bool wFileIO::saveFile(const char* pContentString, const std::string& pFileName)
{
std::string fn=convertPathFormatToUnixStyle(pFileName);
int np=fn.rfind('/');
if(np!=std::string::npos)
if(!mkDirM(fn.substr(0,np)))
return false;
std::string path = getWritablePath()+fn;
FILE* file = fopen(path.c_str(), "w");
if (file)
{
fputs(pContentString, file);
fclose(file);
log("save file [%s]",path.c_str());
return true;
}
else
log("fail to save file [%s]!",path.c_str());
return false;
}
//檢測各級資料夾,不存在則建立
bool wFileIO::mkDirM(const std::string& pDirName)
{
std::string path = getWritablePath();
int np=pDirName.find('/',0);
while(np!=std::string::npos)
{
if(!mkDir(path+pDirName.substr(0,np)))
return false;
np=pDirName.find('/',np+1);
}
return mkDir(path+pDirName);
}
//建立資料夾
bool wFileIO::mkDir(const std::string& pDirName)
{
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32)
DIR *pDir = NULL;
//開啟該路徑
pDir = opendir (pDirName.c_str());
if (! pDir)
{
//建立該路徑
if(!mkdir(pDirName.c_str(), S_IRWXU | S_IRWXG | S_IRWXO))
{
log("fail to create dir [%s]",pDirName.c_str());
return false;
}
log("create dir [%s]",pDirName.c_str());
}
#else
if ((GetFileAttributesA(pDirName.c_str())) == INVALID_FILE_ATTRIBUTES)
{
if(!CreateDirectoryA(pDirName.c_str(), 0))
{
log("fail to create dir [%s]",pDirName.c_str());
return false;
}
log("create dir [%s]",pDirName.c_str());
}
#endif
return true;
}
//路徑格式轉為UnixStyle,"c:\xxx.txt" --> "c:/xxx.txt"
static inline std::string convertPathFormatToUnixStyle(const std::string& path)
{
std::string ret = path; int len = ret.length();
for (int i = 0; i < len; ++i)
{
if (ret[i] == '\\')
{
ret[i] = '/';
}
}
return ret;
}
好了,Cocos2dx中的檔案操作就學習到這裡了。