1. 程式人生 > >[cocos2dx 3.0 (一)] 對檔案讀寫操作 +FileUtils類

[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中的檔案操作就學習到這裡了。吐舌頭