在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/",//m_searchResolutionsOrderArray
and set three elements("resources-ipadhd/","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;
}
总结:这里需要知道一点,就是先加载搜索路径的路径,会优先搜索到。
比如热更新,我们只要把更新路径设置在前面即可。
原文链接:https://www.f2er.com/cocos2dx/343676.html