cocos2dx-2.x CCFileUtils檔案管理類分析
cocos2dx檔案管理類是一個很重要的類,這裡對這個類進行一下分析: CCFileUtils是檔案管理類的基類,不同平臺下android,ios,win32都有 繼承於這個類的子類,如android class CC_DLL CCFileUtilsAndroid : public CCFileUtils 1、單例類: static CCFileUtils* sharedFileUtils() 而實現卻在CCFileUtilsAndroid.cpp檔案中:並且建立的是各個平臺下的子類例項 CCFileUtils* CCFileUtils::sharedFileUtils() { if (s_sharedFileUtils == NULL) { s_sharedFileUtils = new CCFileUtilsAndroid(); s_sharedFileUtils->init(); //獲取apk包的路徑,這裡是java端設定的。 std::string resourcePath = getApkPath(); // record the zip on the resource path // static ZipFile *s_pZipFile = NULL; // 因為android的很多資源是放在安裝包裡的assets檔案裡, //所以獲取資源是需要從包裡解壓,這就用到了ZipFile類 s_pZipFile = new ZipFile(resourcePath, "assets/"); } return s_sharedFileUtils; } 2、初始化: bool CCFileUtilsAndroid::init() { m_strDefaultResRootPath = "assets/"; //預設的資源路徑,預設是安裝包 return CCFileUtils::init(); -->> 1 } 1 -->> bool CCFileUtils::init() { //m_searchPathArray -- 資源搜尋路徑陣列 //m_searchResolutionsOrderArray -- 資源解析度陣列 m_searchPathArray.push_back(m_strDefaultResRootPath); m_searchResolutionsOrderArray.push_back(""); return true; }
在1中,我只是針對整體結構進行了分析,那麼在2中,我將會對一些我們常用的函式進行分析。 //獲取給定檔名的全路徑 //下面這很長一段註釋,通過舉例子,像我們說明cocos2dx獲取檔案全路徑的規則。 //這段我就不翻譯了,直接通過程式碼來看。 /** Returns the fullpath for a given filename. First it will try to get a new filename from the "filenameLookup" dictionary. If a new filename can't be found on the dictionary, it will use the original filename. Then it will try to obtain the full path of the filename using the CCFileUtils search rules: resolutions, and search paths. The file search is based on the array element order of search paths and resolution directories. For instance: We set two elements("/mnt/sdcard/", "internal_dir/") to search paths vector by setSearchPaths, and set three elements("resources-ipadhd/", "resources-ipad/", "resources-iphonehd") to resolutions vector by setSearchResolutionsOrder. The "internal_dir" is relative to "Resources/". If we have a file named 'sprite.png', the mapping in fileLookup dictionary contains `key: sprite.png -> value: sprite.pvr.gz`. Firstly, it will replace 'sprite.png' with 'sprite.pvr.gz', then searching the file sprite.pvr.gz as follows: /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") If the filename contains relative path like "gamescene/uilayer/sprite.png", and the mapping in fileLookup dictionary contains `key: gamescene/uilayer/sprite.png -> value: gamescene/uilayer/sprite.pvr.gz`. The file search order will be: /mnt/sdcard/gamescene/uilayer/resources-ipadhd/sprite.pvr.gz (if not found, search next) /mnt/sdcard/gamescene/uilayer/resources-ipad/sprite.pvr.gz (if not found, search next) /mnt/sdcard/gamescene/uilayer/resources-iphonehd/sprite.pvr.gz (if not found, search next) /mnt/sdcard/gamescene/uilayer/sprite.pvr.gz (if not found, search next) internal_dir/gamescene/uilayer/resources-ipadhd/sprite.pvr.gz (if not found, search next) internal_dir/gamescene/uilayer/resources-ipad/sprite.pvr.gz (if not found, search next) internal_dir/gamescene/uilayer/resources-iphonehd/sprite.pvr.gz (if not found, search next) internal_dir/gamescene/uilayer/sprite.pvr.gz (if not found, return "gamescene/uilayer/sprite.png") If the new file can't be found on the file system, it will return the parameter pszFileName directly. @since v2.1 */ virtual std::string fullPathForFilename(const char* pszFileName); -->> std::string CCFileUtils::fullPathForFilename(const char* pszFileName) { CCAssert(pszFileName != NULL, "CCFileUtils: Invalid path"); //判斷是否是絕對路徑,如果是絕對路徑就直接返回。 /* //android下 判斷依據就是是否以'/'開頭或者以assets/開頭。下面這個函式,註釋的很清楚。 //你可以做個實驗: //例: Get data from file(/second_bg.png) failed! 我在建立精靈時傳遞/second_bg.png路徑 bool CCFileUtilsAndroid::isAbsolutePath(const std::string& strPath) { // On Android, there are two situations for full path. // 1) Files in APK, e.g. assets/path/path/file.png // 2) Files not in APK, e.g. /data/data/org.cocos2dx.hellocpp/cache/path/path/file.png, or /sdcard/path/path/file.png. // So these two situations need to be checked on Android. if (strPath[0] == '/' || strPath.find(m_strDefaultResRootPath) == 0) { return true; } return false; } */ std::string strFileName = pszFileName; if (isAbsolutePath(pszFileName)) { //CCLOG("Return absolute path( %s ) directly.", pszFileName); return pszFileName; } // Already Cached ? //是否已經快取,如果快取過,直接返回 std::map<std::string, std::string>::iterator cacheIter = m_fullPathCache.find(pszFileName); if (cacheIter != m_fullPathCache.end()) { //CCLOG("Return full path from cache: %s", cacheIter->second.c_str()); return cacheIter->second; } /* std::string CCFileUtils::getNewFilename(const char* pszFileName) { const char* pszNewFileName = NULL; // in Lookup Filename dictionary ? //可以把這個m_pFilenameLookupDict(預設為NULL)字典理解為一種查詢 //比如這個字典裡存了一個"fish.png(key)" --> "big_fish.png(value)" //那麼我們傳入fish.png是,就會給我們轉化為big_fish.png。如果沒有,則返回我們傳入的。 CCString* fileNameFound = m_pFilenameLookupDict ? (CCString*)m_pFilenameLookupDict->objectForKey(pszFileName) : NULL; if( NULL == fileNameFound || fileNameFound->length() == 0) { pszNewFileName = pszFileName; } else { pszNewFileName = fileNameFound->getCString(); //CCLOG("FOUND NEW FILE NAME: %s.", pszNewFileName); } return pszNewFileName; } */ // Get the new file name. std::string newFilename = getNewFilename(pszFileName); string fullpath = ""; //下面這一段很關鍵: //m_searchPathArray 前面介紹過搜尋路徑陣列,需要我們手動設定。android的初始話會新增一個預設值為 //m_searchPathArray.push_back(m_strDefaultResRootPath)即,"assets/"。 /* m_searchResolutionsOrderArray 可以理解為解析度搜尋順序,就按開頭註釋說明的那樣 //m_searchPathArray We set two elements("/mnt/sdcard/", "internal_dir/") to search paths vector by setSearchPaths, //m_searchResolutionsOrderArray and set three elements("resources-ipadhd/", "resources-ipad/", "resources-iphonehd") to resolutions vector by setSearchResolutionsOrder. //組合後的路徑 /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) 總結:從這裡可以看出,m_searchPathArray在前面的路徑,會優先搜尋,m_searchResolutionsOrderArray也一樣。 */ for (std::vector<std::string>::iterator searchPathsIter = m_searchPathArray.begin(); searchPathsIter != m_searchPathArray.end(); ++searchPathsIter) { for (std::vector<std::string>::iterator resOrderIter = m_searchResolutionsOrderArray.begin(); resOrderIter != m_searchResolutionsOrderArray.end(); ++resOrderIter) { //CCLOG("\n\nSEARCHING: %s, %s, %s", newFilename.c_str(), resOrderIter->c_str(), searchPathsIter->c_str()); //下面我分析一下這個函式:-->> 2 fullpath = this->getPathForFilename(newFilename, *resOrderIter, *searchPathsIter); //這裡會對找到的路徑,進行快取 if (fullpath.length() > 0) { // Using the filename passed in as key. m_fullPathCache.insert(std::pair<std::string, std::string>(pszFileName, fullpath)); //CCLOG("Returning path: %s", fullpath.c_str()); return fullpath; } } } //CCLOG("cocos2d: fullPathForFilename: No file found at %s. Possible missing file.", pszFileName); // The file wasn't found, return the file name passed in. return pszFileName; } --> 2 //filename -- 傳入的檔名 //searchPath -- 搜尋路徑 //resolutionDirectory -- 資源解析度路徑 std::string CCFileUtils::getPathForFilename(const std::string& filename, const std::string& resolutionDirectory, const std::string& searchPath) { std::string file = filename; std::string file_path = ""; size_t pos = filename.find_last_of("/"); if (pos != std::string::npos) { file_path = filename.substr(0, pos+1); file = filename.substr(pos+1); } //如果傳入的"gamescene/uilayer/sprite.png"是這樣的路徑,那麼進行一定的處理, //處理成:path = searchPath + gamescene/uilayer/ + resourceDirectory file = sprite.png ///mnt/sdcard/ gamescene/uilayer/ resources-ipadhd/sprite.pvr.gz // searchPath + file_path + resourceDirectory std::string path = searchPath; path += file_path; path += resolutionDirectory; path = getFullPathForDirectoryAndFilename(path, file); //CCLOG("getPathForFilename, fullPath = %s", path.c_str()); return path; } -->> std::string CCFileUtils::getFullPathForDirectoryAndFilename(const std::string& strDirectory, const std::string& strFilename) { std::string ret = strDirectory+strFilename; //如果檔案存在,就把檔案的路徑返回,這個路徑可能是絕對路徑,也可能是包裡的路徑 if (!isFileExist(ret)) { ret = ""; } return ret; } -->> //把上面合成的整個檔案路徑傳進去,判斷檔案是否存在 bool CCFileUtilsAndroid::isFileExist(const std::string& strFilePath) { if (0 == strFilePath.length()) { return false; } bool bFound = false; // Check whether file exists in apk. //如果不是以'/'開頭,就在android包裡查詢 if (strFilePath[0] != '/') { //如果不是以"assets/"開頭,則插入 std::string strPath = strFilePath; if (strPath.find(m_strDefaultResRootPath) != 0) {// Didn't find "assets/" at the beginning of the path, adding it. strPath.insert(0, m_strDefaultResRootPath); } //在安裝包裡查詢,看是否存在 if (s_pZipFile->fileExists(strPath)) { bFound = true; } } else { //如果是絕對路徑,看否開啟成功,如果成功,則證明檔案存在。 FILE *fp = fopen(strFilePath.c_str(), "r"); if(fp) { bFound = true; fclose(fp); } } return bFound; } 總結:這裡需要知道一點,就是先載入搜尋路徑的路徑,會優先搜尋到。 比如熱更新,我們只要把更新路徑設定在前面即可。
在2中,我們分析了幾個函式,在這一篇中我們繼續分析其他一些函式。 1、 在2中,多次用到了m_searchPathArray(搜尋路徑),那這個搜尋路徑怎麼來的呢? 我們可以通過setSearchPaths這個函式來設定搜尋路徑 void CCFileUtils::setSearchPaths(const std::vector<std::string>& searchPaths) { bool bExistDefaultRootPath = false; //先把以前的清空,包括快取路徑 m_fullPathCache.clear(); m_searchPathArray.clear(); //逐個加入到m_searchPathArray for (std::vector<std::string>::const_iterator iter = searchPaths.begin(); iter != searchPaths.end(); ++iter) { std::string strPrefix; std::string path; //如果不是絕對路徑,android的則加上"assets/"字首,表明需要去安裝包裡找 if (!isAbsolutePath(*iter)) { // Not an absolute path strPrefix = m_strDefaultResRootPath; } //如果路徑不是以'/'結尾,則在結尾加上'/' path = strPrefix+(*iter); if (path.length() > 0 && path[path.length()-1] != '/') { path += "/"; } if (!bExistDefaultRootPath && path == m_strDefaultResRootPath) { bExistDefaultRootPath = true; } m_searchPathArray.push_back(path); } if (!bExistDefaultRootPath) { //如果m_strDefaultResRootPath預設路徑不在m_searchPathArray,則加入進來 //CCLOG("Default root path doesn't exist, adding it."); m_searchPathArray.push_back(m_strDefaultResRootPath); } } -->> void CCFileUtils::addSearchPath(const char* path_) { std::string strPrefix; std::string path(path_); if (!isAbsolutePath(path)) { // Not an absolute path strPrefix = m_strDefaultResRootPath; } path = strPrefix + path; if (path.length() > 0 && path[path.length()-1] != '/') { path += "/"; } m_searchPathArray.push_back(path); } //移除一個搜尋路徑: void CCFileUtils::removeSearchPath(const char *path_) { std::string strPrefix; std::string path(path_); if (!isAbsolutePath(path)) { // Not an absolute path strPrefix = m_strDefaultResRootPath; } path = strPrefix + path; if (path.length() > 0 && path[path.length()-1] != '/') { path += "/"; } std::vector<std::string>::iterator iter = std::find(m_searchPathArray.begin(), m_searchPathArray.end(), path); m_searchPathArray.erase(iter); } //移除全部 void CCFileUtils::removeAllPaths() { m_searchPathArray.clear(); } 2、 m_searchResolutionsOrderArray資源路徑和上面的一樣處理方式,就不說了。 3、 從pszRelativeFile這個檔案的相對路徑中,得到pszFilename檔案的全路徑, 其實就是找到pszRelativeFile檔案的最後一個'/',然後去這個'/'前的所有字元 + pszFilename即可。 const char* CCFileUtils::fullPathFromRelativeFile(const char *pszFilename, const char *pszRelativeFile) { std::string relativeFile = pszRelativeFile; CCString *pRet = CCString::create(""); pRet->m_sString = relativeFile.substr(0, relativeFile.rfind('/')+1); pRet->m_sString += getNewFilename(pszFilename); return pRet->getCString(); } 4、 //android下的可讀寫路徑 string CCFileUtilsAndroid::getWritablePath() { // Fix for Nexus 10 (Android 4.2 multi-user environment) // the path is retrieved through Java Context.getCacheDir() method string dir(""); //pContext.getFilesDir().getAbsolutePath() java端 string tmp = getFileDirectoryJNI(); //pContext.getFilesDir().getAbsolutePath() if (tmp.length() > 0) { dir.append(tmp).append("/"); return dir; } else { return ""; } }
在3中,我們又分析了幾個函式,在這一篇中我們繼續分析其他一些函式。
1、android平臺
unsigned char* CCFileUtilsAndroid::getFileData(const char* pszFileName, const char* pszMode, unsigned long * pSize)
{
return doGetFileData(pszFileName, pszMode, pSize, false);
}
-->>
//pszFileName 檔名
//pszMode 讀取模式,只有對絕對路徑有用,引數就是C API的型別
//pSize 讀出的位元組大小
//forAsync 同步還是非同步
unsigned char* CCFileUtilsAndroid::doGetFileData(const char* pszFileName, const char* pszMode, unsigned long * pSize, bool forAsync)
{
unsigned char * pData = 0;
if ((! pszFileName) || (! pszMode) || 0 == strlen(pszFileName))
{
return 0;
}
//先獲取檔案的全路徑
string fullPath = fullPathForFilename(pszFileName);
if (fullPath[0] != '/')
{
//如果以"assets/"開頭,即檔案在安裝包裡,那麼通過壓縮檔案類從壓縮包中讀取,
//其實android的安裝包就是壓縮包。
if (forAsync)
{
pData = s_pZipFile->getFileData(fullPath.c_str(), pSize, s_pZipFile->_dataThread);
}
else
{
pData = s_pZipFile->getFileData(fullPath.c_str(), pSize);
}
}
else
{
do
{
//如果是絕對路徑,則通過C API讀取。
// read rrom other path than user set it
//CCLOG("GETTING FILE ABSOLUTE DATA: %s", pszFileName);
FILE *fp = fopen(fullPath.c_str(), pszMode);
CC_BREAK_IF(!fp);
unsigned long size;
fseek(fp,0,SEEK_END);
size = ftell(fp);
fseek(fp,0,SEEK_SET);
pData = new unsigned char[size];
size = fread(pData,sizeof(unsigned char), size,fp);
fclose(fp);
if (pSize)
{
*pSize = size;
}
} while (0);
}
if (! pData)
{
std::string msg = "Get data from file(";
msg.append(pszFileName).append(") failed!");
CCLOG("%s", msg.c_str());
}
return pData;
}
總結:到此為止,cocos2dx-2.X android平臺的檔案讀出我已經通過原始碼的形式分析完了,做個記錄,
以防忘記。
相關推薦
cocos2dx-2.x CCFileUtils檔案管理類分析
cocos2dx檔案管理類是一個很重要的類,這裡對這個類進行一下分析: CCFileUtils是檔案管理類的基類,不同平臺下android,ios,win32都有 繼承於這個類的子類,如android class CC_DLL CCFileUtilsAndroid :
漲姿勢:Spring Boot 2.x 啟動全過程源碼分析
nlog res ces framework abs rsh 思路 get spec 上篇《Spring Boot 2.x 啟動全過程源碼分析(一)入口類剖析》我們分析了 Spring Boot 入口類 SpringApplication 的源碼,並知道了其構造原理,這篇我
linux學習筆記(2):檔案管理
1. 建立 建立檔案 touch 檔名 舉例:touch file1 flie2 flie3… 新建目錄 mkdir 目錄名 舉例:mldir dir 建立遞迴目錄 mkdir -p 目錄名/目錄名/目錄名… 舉例:mkdir -p dir1/dir2/dir3 2. 刪除 刪除檔案
django 2.x + celery 4.2.x 配置檔案 設定
django 2.x + celery 4.2.x配置 模組 celery==4.2.1 django-celery-beat==1.1.1 django-celery-results==1.0.1 kombu==4.2.1 配置 __init__.py from __future__ import
linux上檔案管理類命令總結
Linux上的檔案管理類命令有三個,分別是:cp、mv、rm命令。 cp: 複製檔案和目錄的命令。cp命令分為兩種,分別是:單源複製和多源複製: 單源複製: 如果目標檔案和目錄(DEST)不存在,則實現建立此檔案,並複製原始檔的資料流至DEST中。
解決springboot 2.x 移除了 SocialAutoConfiguerAdapter類註冊connectionFactory的問題
1.5x的springboot在 AutoConfig social 包下面有個SocialAutoConfigurerAdapter類 之前如果要生產一個OAuth2ConnectionFactory的連線工廠,只需要繼承這個類,重寫一個ConnectionFactory
hadoop 2.X 命令檔案目錄的變化
lll 增加./bin/yarn命令。原來1.x中對JobTracker及TaskTracker的管理,放到了新增的yarn命令中,該命令可以啟動及管理ResourceManager、在每臺slave上面都啟一個NodeManager、執行一個JAR或CLASS檔案、列印需要的classpath、列印應用程式
AFN網路框架2.x版—檔案上傳
/** * 檔案上傳 */ - (void)uploadFile { //1.獲得請求管理者 AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
X配置檔案xorg.conf分析
XF86Config說明 檔案的每節都是由下述的部分組成: Section "SectionName" SectionEntry … EndSection SectionName包括: Files 檔案路徑名 ServerFlags 伺服器標誌 Module 動態模組載入 Inp
cocos2dx[2.x](22)--簡單碰撞檢測
【嘮叨】 本節來講講簡單的物理碰撞檢測(非Box2D物理碰撞):矩形、圓之間的碰撞檢測。 【3.x】 將數學類 CCPoint、CCRect 改為v3.x版本的 Vec2、Rect 就好了。 【簡單碰撞檢測】 在一些遊戲中經常會遇到碰撞檢測的情況,
cocos2dx-2.x的eclipse打包apk
必備安裝環境:java jdk安裝以及環境變數,python執行環境 cocos2dx 2.2.2版本是通過python指令碼建立的,指令碼位置:cocos2d-x-2.2.2\tools\project-creator\create_project.py; 這裡可以
linux上的檔案管理類命令有哪些,常用的使用方法及其相關例項演示
Linux 一切皆檔案。個人理解 在linux下的命令操作都算是對檔案操作 那麼檔案管理命令類命令可以分為下面幾類 目錄操作: 特殊目錄解釋: . 代表此層目錄;.. 代表上一層目錄;- 代表前一個目錄;~ 代表當前使用者的主資料夾 也可以稱為家目錄
cocos2dx[2.x](19)--基本動畫CCAnimation/CCAnimate
【嘮叨】 基本動畫製作需要用到CCAnimation類,用於儲存動畫相關的資訊。以及由CCActionInterval繼承的CCAnimate動畫動作。 還有一些在建立動畫動作的過程中,可能會用到的一些類CCSpriteFrame、CCSpriteFrameC
JAVA開發經驗(二):常用工具類2.1-IO-檔案操作類(FileUtil)
摘要說明: FileUtil主要是整合Apache Commons IO庫中的FileUtils類;主要包括對檔案的屬性查詢,複製,移動,檔案讀取,刪除等 Apache Commons IO庫包含實用程式類,流實現,檔案過濾器,檔案比較器,位元組序轉換類等等 Maven
cocos2dx[2.x](17)--擴充套件動作CCGridAction
【嘮叨】 CCActionInterval除了上節講的基本動作外,還有其他許多的擴充套件動作CCGridAction。顧名思義,就是將顯示的內容分為一塊塊小格子,然後在格子的基礎上進行一些圖形的變換。 【3.x】 (1)去掉“CC” (2)其他變化不
將舊專案基於cocos2dx 2.x的除錯繪製轉移到cocos2dx 3.x中
1、首先必須修改原先在draw函式中繪製渲染的方式。3.x不是直接呼叫draw函式進行繪製的,而是通過renderCommand進行延時渲染。 老專案的渲染方式-draw函式中呼叫 #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS
cocos2d-x 3.0 ref類分析
ref類是cocos2dx引擎的基類 許多類都繼承於它 那麼為什麼呢? 我們先看看原始碼 class CC_DLL Ref { public: //計數加1 void retain()
cocos2dx[2.x](16)--基本動作CCAction
【嘮叨】 在電影裡,角色的運動就是動作。而在遊戲裡,動畫就是角色的動作了。例如人物走動、跳躍、釋放魔法,鳥兒飛翔,車輪滾動等。動作是遊戲中不可或缺的重要組成部分,使得遊戲更具魅力,變得豐富活力。 cocos2dx引擎為我們提供了十分豐富的CCAction動作系
cocos2dx 2.x版本在android下CCLabelTTF的一個bug
cocos2dx在android下是採用Paint來生成圖片然後在CCLabelTTF裡顯示的,它具體的程式碼都在java類Cocos2dxBitmap裡,生成完成之後會呼叫一個jni函式將結果傳給cpp層,cpp層靠一個static變數來與java層交換資料,具體如下
cocos2dx.3.x之重要類分析(1)——Ref
Ref ref類是cocos2dx引擎的基類 許多類都繼承於它 那麼為什麼呢? 我們先看看原始碼 class CC_DLL Ref { public: void retain(); void release(); Ref* autorel