[✔️]cocos2dx的CCFileUtils深度理解

452 阅读2分钟

重点看在Android上的实现

image.png

  • CCFileUtils-android.cpp
FileUtils* FileUtils::getInstance()
{
    if (s_sharedFileUtils == nullptr)
    {
        // Android的类
        s_sharedFileUtils = new FileUtilsAndroid();
    }
    return s_sharedFileUtils;
}
std::string FileUtils::fullPathForFilename(const std::string &filename) const{
    std::string fullpath;
    // 这个_searchPathArray里面就有assets这个很特殊的目录
    for (const auto& searchIt : _searchPathArray) {
        for (const auto& resolutionIt : _searchResolutionsOrderArray) {
            // 里面有平台代码,换取fullpath
            fullpath = this->getPathForFilename(newFilename, resolutionIt, searchIt);
            if (!fullpath.empty()) {
                // Using the filename passed in as key.
                _fullPathCache.emplace(name, fullpath);
                return fullpath;
            }
        }
    }
}
// 最终会来到这个函数
std::string FileUtils::getFullPathForDirectoryAndFilename(const std::string& directory, const std::string& filename) const {
    // get directory+filename, safely adding '/' as necessary
    std::string ret = directory;
    if (directory.size() && directory[directory.size()-1] != '/'){
        ret += '/';
    }
    ret += filename;
    // if the file doesn't exist, return an empty string
    if (!isFileExistInternal(ret)) {
        ret = "";
    }
    return ret;
}
// 安卓平台判断文件是否是内置的资源
bool FileUtilsAndroid::isFileExistInternal(const std::string& strFilePath) const
{
    if (strFilePath.empty()) {
        return false;
    }
    bool bFound = false;
    // Check whether file exists in apk.
    if (strFilePath[0] != '/') {
        const char* s = strFilePath.c_str();
        // Found "assets/" at the beginning of the path and we don't want it
        // 注意这个_defaultResRootPath,它是一个protected变量,在init有赋值
        if (strFilePath.find(_defaultResRootPath) == 0) s += _defaultResRootPath.length();
        if (obbfile && obbfile->fileExists(s)) {
            bFound = true;
        }else if (FileUtilsAndroid::assetmanager){
            // 看到了Android平台的jni代码
            AAsset* aa = AAssetManager_open(FileUtilsAndroid::assetmanager, s, AASSET_MODE_UNKNOWN);
            if (aa){
                bFound = true;
                AAsset_close(aa);
            } else {
                // CCLOG("[AssetManager] ... in APK %s, found = false!", strFilePath.c_str());
            }
        }
    }
    else {
        FILE *fp = fopen(strFilePath.c_str(), "r");
        if (fp) {
            bFound = true;
            fclose(fp);
        }
    }
    return bFound;
}

#define  ASSETS_FOLDER_NAME          "assets/"

bool FileUtilsAndroid::init()
{
    _defaultResRootPath = ASSETS_FOLDER_NAME;
    // ...
}

void FileUtils::setSearchPaths(const std::vector<std::string>& searchPaths)
{
    // 每一次添加searchpaths的时候,都会检查rootPath的存在
    bool existDefaultRootPath = false;
    // ...
    if (!existDefaultRootPath) {
        _searchPathArray.push_back(_defaultResRootPath);
    }
}

安卓平台的搜索路径:

  • assets/src/
  • assets/res/
  • assets/

至此也就搞明白了,fullpath在Android上是一个假的路径

由于assets文件夹中的文件在APK文件中被打包,因此它们没有绝对路径。


string FileUtilsAndroid::getWritablePath() const
{
    // Fix for Nexus 10 (Android 4.2 multi-user environment)
    // the path is retrieved through Java Context.getCacheDir() method
    string dir("");
    string tmp = JniHelper::callStaticStringMethod("org/cocos2dx/lib/Cocos2dxHelper", "getCocos2dxWritablePath");

    if (tmp.length() > 0)
    {
        dir.append(tmp).append("/");

        return dir;
    }
    else
    {
        return "";
    }
}
public static String getCocos2dxWritablePath() {
    //赋值的逻辑: Cocos2dxHelper.sFileDirectory = activity.getFilesDir().getAbsolutePath();
    return Cocos2dxHelper.sFileDirectory;
}

Android的各种dir

目录方法路径特点和用途卸载应用程序时是否会被删除
getDir()/data/data/包名/app_data/自定义目录名应用程序的私有数据目录,通常用于存储应用程序的数据库文件或其他私有数据。可以指定自定义目录
getFilesDir()/data/data/包名/files应用程序的私有文件目录,通常用于存储应用程序的数据文件。 固定目录
getCacheDir()/data/data/包名/cache应用程序的私有缓存目录,通常用于存储临时文件或缓存数据。
getExternalFilesDir()/storage/emulated/0/Android/data/包名/files应用程序在外部存储设备上的私有文件目录,通常用于存储需要与其他应用程序共享的数据文件。
getExternalCacheDir()/storage/emulated/0/Android/data/包名/cache应用程序在外部存储设备上的缓存目录,通常用于存储临时文件或缓存数据。