cocos2dx 3.6源码分析之文件路径
cocos2dx中资源文件都放在Resources目录中,编译后会自动复制到exe所在的目录中。
核心类是FileUtils类,一个单例类。
三个重要的函数
void addSearchPath(const std::string & path, const bool front=false); virtual void addSearchResolutionsOrder(const std::string &order,const bool front=false); virtual std::string fullPathForFilename(const std::string &filename) const;
依次分析。
void FileUtils::addSearchPath(const std::string &searchpath,const bool front) { std::string prefix; if (!isAbsolutePath(searchpath)) prefix = _defaultResRootPath; std::string path = prefix + searchpath; if (path.length() > 0 && path[path.length()-1] != '/') { path += "/"; } if (front) { _searchPathArray.insert(_searchPathArray.begin(), path); } else { _searchPathArray.push_back(path); } }
核心数据成员_searchPathArray,首先判断是否是绝对路径,如果不是则通过平台相关的默认资源根路径得到前缀prefix。其次判断给定的字符串后有没有/,没有则加上。
第二个参数font代表搜索优先级,有优先级则插入到_searchPathArray的前端,否则放入后面。vector用Insert感觉还挺奇怪的。
void FileUtils::addSearchResolutionsOrder(const std::string &order,const bool front) { std::string resOrder = order; if (!resOrder.empty() && resOrder[resOrder.length()-1] != '/') resOrder.append("/"); if (front) { _searchResolutionsOrderArray.insert(_searchResolutionsOrderArray.begin(), resOrder); } else { _searchResolutionsOrderArray.push_back(resOrder); } }
核心数据成员_searchResolutionsOrderArray,这里我理解为子目录,Resolutions这命名用在这里让我十分费解。同样如果传入字符串尾部没有/则加/。如果有优先级顺序则加入都头部,否则尾部。
下面就是重头戏了,查找路径的时候如何拼接目录和子目录为一个字符串。
std::string FileUtils::fullPathForFilename(const std::string &filename) const { if (filename.empty()) { return ""; } if (isAbsolutePath(filename)) { return filename; } // Already Cached ? auto cacheIter = _fullPathCache.find(filename); if(cacheIter != _fullPathCache.end()) { return cacheIter->second; } // Get the new file name. const std::string newFilename( getNewFilename(filename) ); std::string fullpath; for (const auto& searchIt : _searchPathArray) { for (const auto& resolutionIt : _searchResolutionsOrderArray) { fullpath = this->getPathForFilename(newFilename, resolutionIt, searchIt); if (fullpath.length() > 0) { // Using the filename passed in as key. _fullPathCache.insert(std::make_pair(filename, fullpath)); return fullpath; } } } if(isPopupNotify()){ CCLOG("cocos2d: fullPathForFilename: No file found at %s. Possible missing file.", filename.c_str()); } // The file wasn't found, return empty string. return ""; }
这段代码思路,就是传入一个文件名,如何在资源路径中找到绝对路径的全名出来。这里就要用到之前的搜索路径和子路径了。
首先判断是否为空和是否为绝对路径,以"/"开头被认为是绝对路径则直接返回。然后再看有没有再文件缓存里面如果有则直接返回。
如果都没有则开始拼接一个新的绝对路径出来。这里就用到了前面添加的2个重要的数据成员_searchPathArray和_searchResolutionsOrderArray。
首先对_searchPathArray进行遍历,在每一个_searchPathArray成员中再对_searchResolutionsOrderArray进行遍历。
然后进入核心拼接函数。
std::string FileUtils::getPathForFilename(const std::string& filename, const std::string& resolutionDirectory, const std::string& searchPath) const { 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); } // 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; }
找到最后一个"/"出现的位置,如果filename字符串中没有"/",则Path = searchPath + resolutionDirectory,这里path只是文件夹路径,所以searchPath和resolutionDirectory也可以是多级目录路径。
getFullPathForDirectoryAndFilename会把目录路径和文件路径拼接起来。最后得到一个完整的path。