重点看在Android上的实现
- 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 | 应用程序在外部存储设备上的缓存目录,通常用于存储临时文件或缓存数据。 | 否 |