Skip to content

Commit ed34e02

Browse files
PatriceJianghuangwei1024
authored andcommitted
[cpp-tests] Fileutils performance issue fix (cocos2d#19231)
- rename getFullPathForDirectoryAndFilename to getFullPathForFilenameWithinDirectory - add fullPathForDirectory, seperated from fullPathForFilename - add test case for FileUtils::listFiles
1 parent 2eee8b8 commit ed34e02

12 files changed

+143
-22
lines changed

cocos/platform/CCFileUtils.cpp

+62-8
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,7 @@ std::string FileUtils::getPathForFilename(const std::string& filename, const std
808808
path += file_path;
809809
path += resolutionDirectory;
810810

811-
path = getFullPathForDirectoryAndFilename(path, file);
811+
path = getFullPathForFilenameWithinDirectory(path, file);
812812

813813
return path;
814814
}
@@ -864,6 +864,60 @@ std::string FileUtils::fullPathForFilename(const std::string &filename) const
864864
return "";
865865
}
866866

867+
868+
std::string FileUtils::fullPathForDirectory(const std::string &dir) const
869+
{
870+
DECLARE_GUARD;
871+
872+
if (dir.empty())
873+
{
874+
return "";
875+
}
876+
877+
if (isAbsolutePath(dir))
878+
{
879+
return dir;
880+
}
881+
882+
// Already Cached ?
883+
auto cacheIter = _fullPathCacheDir.find(dir);
884+
if(cacheIter != _fullPathCacheDir.end())
885+
{
886+
return cacheIter->second;
887+
}
888+
std::string longdir = dir;
889+
std::string fullpath;
890+
891+
if(longdir[longdir.length() - 1] != '/')
892+
{
893+
longdir +="/";
894+
}
895+
896+
for (const auto& searchIt : _searchPathArray)
897+
{
898+
for (const auto& resolutionIt : _searchResolutionsOrderArray)
899+
{
900+
fullpath = searchIt + longdir + resolutionIt;
901+
auto exists = isDirectoryExistInternal(fullpath);
902+
903+
if (exists && !fullpath.empty())
904+
{
905+
// Using the filename passed in as key.
906+
_fullPathCacheDir.emplace(dir, fullpath);
907+
return fullpath;
908+
}
909+
910+
}
911+
}
912+
913+
if(isPopupNotify()){
914+
CCLOG("cocos2d: fullPathForDirectory: No directory found at %s. Possible missing directory.", dir.c_str());
915+
}
916+
917+
// The file wasn't found, return empty string.
918+
return "";
919+
}
920+
867921
std::string FileUtils::fullPathFromRelativeFile(const std::string &filename, const std::string &relativeFile) const
868922
{
869923
return relativeFile.substr(0, relativeFile.rfind('/')+1) + getNewFilename(filename);
@@ -1053,7 +1107,7 @@ void FileUtils::loadFilenameLookupDictionaryFromFile(const std::string &filename
10531107
}
10541108
}
10551109

1056-
std::string FileUtils::getFullPathForDirectoryAndFilename(const std::string& directory, const std::string& filename) const
1110+
std::string FileUtils::getFullPathForFilenameWithinDirectory(const std::string& directory, const std::string& filename) const
10571111
{
10581112
// get directory+filename, safely adding '/' as necessary
10591113
std::string ret = directory;
@@ -1063,7 +1117,7 @@ std::string FileUtils::getFullPathForDirectoryAndFilename(const std::string& dir
10631117
ret += filename;
10641118

10651119
// if the file doesn't exist, return an empty string
1066-
if (!isFileExistInternal(ret) && !isDirectoryExistInternal(ret)) {
1120+
if (!isFileExistInternal(ret)) {
10671121
ret = "";
10681122
}
10691123
return ret;
@@ -1122,7 +1176,7 @@ bool FileUtils::isDirectoryExist(const std::string& dirPath) const
11221176
for (const auto& resolutionIt : _searchResolutionsOrderArray)
11231177
{
11241178
// searchPath + file_path + resourceDirectory
1125-
fullpath = fullPathForFilename(searchIt + dirPath + resolutionIt);
1179+
fullpath = fullPathForDirectory(searchIt + dirPath + resolutionIt);
11261180
if (isDirectoryExistInternal(fullpath))
11271181
{
11281182
_fullPathCache.emplace(dirPath, fullpath);
@@ -1188,15 +1242,15 @@ void FileUtils::getFileSize(const std::string &filepath, std::function<void(long
11881242

11891243
void FileUtils::listFilesAsync(const std::string& dirPath, std::function<void(std::vector<std::string>)> callback) const
11901244
{
1191-
auto fullPath = fullPathForFilename(dirPath);
1245+
auto fullPath = fullPathForDirectory(dirPath);
11921246
performOperationOffthread([fullPath]() {
11931247
return FileUtils::getInstance()->listFiles(fullPath);
11941248
}, std::move(callback));
11951249
}
11961250

11971251
void FileUtils::listFilesRecursivelyAsync(const std::string& dirPath, std::function<void(std::vector<std::string>)> callback) const
11981252
{
1199-
auto fullPath = fullPathForFilename(dirPath);
1253+
auto fullPath = fullPathForDirectory(dirPath);
12001254
performOperationOffthread([fullPath]() {
12011255
std::vector<std::string> retval;
12021256
FileUtils::getInstance()->listFilesRecursively(fullPath, &retval);
@@ -1459,7 +1513,7 @@ long FileUtils::getFileSize(const std::string &filepath) const
14591513
std::vector<std::string> FileUtils::listFiles(const std::string& dirPath) const
14601514
{
14611515
std::vector<std::string> files;
1462-
std::string fullpath = fullPathForFilename(dirPath);
1516+
std::string fullpath = fullPathForDirectory(dirPath);
14631517
if (isDirectoryExist(fullpath))
14641518
{
14651519
tinydir_dir dir;
@@ -1497,7 +1551,7 @@ std::vector<std::string> FileUtils::listFiles(const std::string& dirPath) const
14971551

14981552
void FileUtils::listFilesRecursively(const std::string& dirPath, std::vector<std::string> *files) const
14991553
{
1500-
std::string fullpath = fullPathForFilename(dirPath);
1554+
std::string fullpath = fullPathForDirectory(dirPath);
15011555
if (isDirectoryExist(fullpath))
15021556
{
15031557
tinydir_dir dir;

cocos/platform/CCFileUtils.h

+15-2
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ class CC_DLL FileUtils
343343
*/
344344
virtual std::string fullPathForFilename(const std::string &filename) const;
345345

346+
346347
/**
347348
* Loads the filenameLookup dictionary from the contents of a filename.
348349
*
@@ -905,8 +906,14 @@ class CC_DLL FileUtils
905906
* @param filename The name of the file.
906907
* @return The full path of the file, if the file can't be found, it will return an empty string.
907908
*/
908-
virtual std::string getFullPathForDirectoryAndFilename(const std::string& directory, const std::string& filename) const;
909+
virtual std::string getFullPathForFilenameWithinDirectory(const std::string& directory, const std::string& filename) const;
910+
909911

912+
/**
913+
* Returns the fullpath for a given dirname.
914+
* @since 3.17.1
915+
*/
916+
virtual std::string fullPathForDirectory(const std::string &dirname) const;
910917

911918
/**
912919
* mutex used to protect fields.
@@ -950,11 +957,17 @@ class CC_DLL FileUtils
950957
std::string _defaultResRootPath;
951958

952959
/**
953-
* The full path cache. When a file is found, it will be added into this cache.
960+
* The full path cache for normal files. When a file is found, it will be added into this cache.
954961
* This variable is used for improving the performance of file search.
955962
*/
956963
mutable std::unordered_map<std::string, std::string> _fullPathCache;
957964

965+
/**
966+
* The full path cache for directories. When a diretory is found, it will be added into this cache.
967+
* This variable is used for improving the performance of file search.
968+
*/
969+
mutable std::unordered_map<std::string, std::string> _fullPathCacheDir;
970+
958971
/**
959972
* Writable path.
960973
*/

cocos/platform/android/CCFileUtils-android.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -227,13 +227,16 @@ bool FileUtilsAndroid::isDirectoryExistInternal(const std::string& dirPath) cons
227227
}
228228
else
229229
{
230+
231+
230232
// find it in apk's assets dir
231233
// Found "assets/" at the beginning of the path and we don't want it
232234
//CCLOG("find in apk dirPath(%s)", s);
233235
if (dirPath.find(ASSETS_FOLDER_NAME) == 0)
234236
{
235237
s += ASSETS_FOLDER_NAME_LENGTH;
236238
}
239+
237240
if (FileUtilsAndroid::assetmanager)
238241
{
239242
AAssetDir* aa = AAssetManager_openDir(FileUtilsAndroid::assetmanager, s);
@@ -295,7 +298,7 @@ std::vector<std::string> FileUtilsAndroid::listFiles(const std::string& dirPath)
295298
if(isAbsolutePath(dirPath)) return FileUtils::listFiles(dirPath);
296299

297300
std::vector<std::string> fileList;
298-
string fullPath = fullPathForFilename(dirPath);
301+
string fullPath = fullPathForDirectory(dirPath);
299302

300303
static const std::string apkprefix("assets/");
301304
string relativePath = "";

cocos/platform/android/CCFileUtils-android.h

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
3434
#include "base/ccTypes.h"
3535
#include <string>
3636
#include <vector>
37+
#include <unordered_map>
38+
#include <memory>
3739
#include "jni.h"
3840
#include "android/asset_manager.h"
3941

cocos/platform/apple/CCFileUtils-apple.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class CC_DLL FileUtilsApple : public FileUtils
5050
virtual ~FileUtilsApple();
5151
/* override functions */
5252
virtual std::string getWritablePath() const override;
53-
virtual std::string getFullPathForDirectoryAndFilename(const std::string& directory, const std::string& filename) const override;
53+
virtual std::string getFullPathForFilenameWithinDirectory(const std::string& directory, const std::string& filename) const override;
5454

5555
virtual ValueMap getValueMapFromFile(const std::string& filename) const override;
5656
virtual ValueMap getValueMapFromData(const char* filedata, int filesize) const override;

cocos/platform/apple/CCFileUtils-apple.mm

+1-1
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ static int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, str
315315
return true;
316316
}
317317

318-
std::string FileUtilsApple::getFullPathForDirectoryAndFilename(const std::string& directory, const std::string& filename) const
318+
std::string FileUtilsApple::getFullPathForFilenameWithinDirectory(const std::string& directory, const std::string& filename) const
319319
{
320320
if (directory[0] != '/')
321321
{

cocos/platform/win32/CCFileUtils-win32.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -220,12 +220,12 @@ std::string FileUtilsWin32::getPathForFilename(const std::string& filename, cons
220220
return FileUtils::getPathForFilename(unixFileName, unixResolutionDirectory, unixSearchPath);
221221
}
222222

223-
std::string FileUtilsWin32::getFullPathForDirectoryAndFilename(const std::string& strDirectory, const std::string& strFilename) const
223+
std::string FileUtilsWin32::getFullPathForFilenameWithinDirectory(const std::string& strDirectory, const std::string& strFilename) const
224224
{
225225
std::string unixDirectory = convertPathFormatToUnixStyle(strDirectory);
226226
std::string unixFilename = convertPathFormatToUnixStyle(strFilename);
227227

228-
return FileUtils::getFullPathForDirectoryAndFilename(unixDirectory, unixFilename);
228+
return FileUtils::getFullPathForFilenameWithinDirectory(unixDirectory, unixFilename);
229229
}
230230

231231
void FileUtilsWin32::listFilesRecursively(const std::string& dirPath, std::vector<std::string> *files) const
@@ -286,7 +286,7 @@ long FileUtilsWin32::getFileSize(const std::string &filepath) const
286286

287287
std::vector<std::string> FileUtilsWin32::listFiles(const std::string& dirPath) const
288288
{
289-
std::string fullpath = fullPathForFilename(dirPath);
289+
std::string fullpath = fullPathForDirectory(dirPath);
290290
std::vector<std::string> files;
291291
if (isDirectoryExist(fullpath))
292292
{

cocos/platform/win32/CCFileUtils-win32.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ class CC_DLL FileUtilsWin32 : public FileUtils
134134
* @param filename The name of the file.
135135
* @return The full path of the file, if the file can't be found, it will return an empty string.
136136
*/
137-
virtual std::string getFullPathForDirectoryAndFilename(const std::string& directory, const std::string& filename) const override;
137+
virtual std::string getFullPathForFilenameWithinDirectory(const std::string& directory, const std::string& filename) const override;
138138

139139
/**
140140
* List all files in a directory.

cocos/platform/winrt/CCFileUtilsWinRT.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,11 @@ std::string CCFileUtilsWinRT::getPathForFilename(const std::string& filename, co
119119
return FileUtils::getPathForFilename(unixFileName, unixResolutionDirectory, unixSearchPath);
120120
}
121121

122-
std::string CCFileUtilsWinRT::getFullPathForDirectoryAndFilename(const std::string& strDirectory, const std::string& strFilename) const
122+
std::string CCFileUtilsWinRT::getFullPathForFilenameWithinDirectory(const std::string& strDirectory, const std::string& strFilename) const
123123
{
124124
std::string unixDirectory = convertPathFormatToUnixStyle(strDirectory);
125125
std::string unixFilename = convertPathFormatToUnixStyle(strFilename);
126-
return FileUtils::getFullPathForDirectoryAndFilename(unixDirectory, unixFilename);
126+
return FileUtils::getFullPathForFilenameWithinDirectory(unixDirectory, unixFilename);
127127
}
128128

129129
std::string CCFileUtilsWinRT::getSuitableFOpen(const std::string& filenameUtf8) const
@@ -380,7 +380,7 @@ string CCFileUtilsWinRT::getWritablePath() const
380380

381381
void CCFileUtilsWinRT::listFilesRecursively(const std::string& dirPath, std::vector<std::string> *files) const
382382
{
383-
std::string fullpath = fullPathForFilename(dirPath);
383+
std::string fullpath = fullPathForDirectory(dirPath);
384384
if (isDirectoryExist(fullpath))
385385
{
386386
tinydir_dir dir;
@@ -426,7 +426,7 @@ void CCFileUtilsWinRT::listFilesRecursively(const std::string& dirPath, std::vec
426426

427427
std::vector<std::string> CCFileUtilsWinRT::listFiles(const std::string& dirPath) const
428428
{
429-
std::string fullpath = fullPathForFilename(dirPath);
429+
std::string fullpath = fullPathForDirectory(dirPath);
430430
std::vector<std::string> files;
431431
if (isDirectoryExist(fullpath))
432432
{

cocos/platform/winrt/CCFileUtilsWinRT.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class CC_DLL CCFileUtilsWinRT : public FileUtils
5252
virtual std::string getWritablePath() const;
5353
virtual bool isAbsolutePath(const std::string& strPath) const;
5454
virtual std::string getPathForFilename(const std::string& filename, const std::string& resolutionDirectory, const std::string& searchPath) const override;
55-
virtual std::string getFullPathForDirectoryAndFilename(const std::string& strDirectory, const std::string& strFilename) const override;
55+
virtual std::string getFullPathForFilenameWithinDirectory(const std::string& strDirectory, const std::string& strFilename) const override;
5656
virtual std::string getSuitableFOpen(const std::string& filenameUtf8) const override;
5757
virtual long getFileSize(const std::string &filepath) override;
5858
virtual FileUtils::Status getContents(const std::string& filename, ResizableBuffer* buffer) override;

tests/cpp-tests/Classes/FileUtilsTest/FileUtilsTest.cpp

+38
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ FileUtilsTests::FileUtilsTests()
4747
ADD_TEST_CASE(TestFileFuncsAsync);
4848
ADD_TEST_CASE(TestWriteStringAsync);
4949
ADD_TEST_CASE(TestWriteDataAsync);
50+
ADD_TEST_CASE(TestListFiles);
5051
}
5152

5253
// TestResolutionDirectories
@@ -1391,3 +1392,40 @@ std::string TestWriteDataAsync::subtitle() const
13911392
{
13921393
return "";
13931394
}
1395+
1396+
void TestListFiles::onEnter()
1397+
{
1398+
FileUtilsDemo::onEnter();
1399+
1400+
auto winSize = Director::getInstance()->getWinSize();
1401+
1402+
auto infoLabel = Label::createWithTTF("show file count, should not be 0", "fonts/Thonburi.ttf", 18);
1403+
this->addChild(infoLabel);
1404+
infoLabel->setPosition(winSize.width / 2, winSize.height * 3 / 4);
1405+
1406+
auto cntLabel = Label::createWithTTF("show readResult", "fonts/Thonburi.ttf", 18);
1407+
this->addChild(cntLabel);
1408+
cntLabel->setPosition(winSize.width / 2, winSize.height / 3);
1409+
// writeTest
1410+
auto list = FileUtils::getInstance()->listFiles("fonts");
1411+
1412+
char cntBuffer[200] = { 0 };
1413+
snprintf(cntBuffer, 200, "%d", list.size());
1414+
cntLabel->setString(cntBuffer);
1415+
1416+
}
1417+
1418+
void TestListFiles::onExit()
1419+
{
1420+
FileUtilsDemo::onExit();
1421+
}
1422+
1423+
std::string TestListFiles::title() const
1424+
{
1425+
return "FileUtils: list files of directory";
1426+
}
1427+
1428+
std::string TestListFiles::subtitle() const
1429+
{
1430+
return "";
1431+
}

tests/cpp-tests/Classes/FileUtilsTest/FileUtilsTest.h

+11
Original file line numberDiff line numberDiff line change
@@ -258,4 +258,15 @@ class TestWriteDataAsync : public FileUtilsDemo
258258
virtual std::string subtitle() const override;
259259
};
260260

261+
class TestListFiles : public FileUtilsDemo
262+
{
263+
public:
264+
CREATE_FUNC(TestListFiles);
265+
266+
virtual void onEnter() override;
267+
virtual void onExit() override;
268+
virtual std::string title() const override;
269+
virtual std::string subtitle() const override;
270+
};
271+
261272
#endif /* __FILEUTILSTEST_H__ */

0 commit comments

Comments
 (0)