在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; } 总结:这里需要知道一点,就是先加载搜索路径的路径,会优先搜索到。 比如热更新,我们只要把更新路径设置在前面即可。
时间: 2024-10-23 06:03:11