详细信息:

UE4通过IPlatformFile支持内置的跨平台文件系统操作。
对于文件系统遍历,它们包括以下方法:

  • IPlatformFile::IterateDirectory
  • IPlatformFile::IterateDirectoryRecursively
  • IPlatformFile::IterateDirectoryStat
  • IPlatformFile::IterateDirectoryStatRecursively

  • 我的目标是填写以下结构:
    struct FFolderNode
    {
    public:
        FFolderNode() : FFolderNode(nullptr, TEXT(""), TEXT("")) {};
        FFolderNode(const FString& Path, const FString& Name) : FFolderNode(nullptr, Path, Name) {};
        FFolderNode(FFolderNode *ParentNode, const FString& Path, const FString& Name) : ParentNode(ParentNode), Path(Path), Name(Name)
        {
            ID = FGuid::NewGuid();
        };
    
        // Makes it easier to identify, map & find this node
        FGuid ID;
        // The name of this directory
        FString Name;
        // The path of this directory
        FString Path;
        // The filenames this directory contains
        TArray<FString> FileNames;
        // The upwards directory (equivalent to the path "..")
        FFolderNode *ParentNode;
        // The subfolders (if any) contained within this directory
        TArray<FFolderNode*> ChildNodes;
    };
    

    我遇到的问题是...
    我将项目的Contents文件夹路径传递给IPlatformFile::IterateDirectory,它执行以下操作:
    c&#43;&#43; - 构建/组织文件系统文件夹的链接列表-LMLPHP

    看起来像字母顺序?所以我不确定从哪里开始。
    似乎我需要能够在创建和分配其父节点之前创建节点,并且没有任何真正的先验所有权知识,除了当前访问的节点是文件还是文件夹,而且它是字符串的完整路径。

    IPlatformFile::FDirectoryVisitor::Visit IterateDirectory调用的递归函数...引擎源代码似乎制作了一个内联类,该内联类继承了 FDirectoryVisitor 并覆盖了此方法,所以这就是我在代码中所做的:
    FFolderNode UDSAssetManager::GetContentTree()
    {
        static auto ContentPath = FPaths::ConvertRelativePathToFull(FPaths::GameContentDir());
    
        class FFolderVisitor : public IPlatformFile::FDirectoryVisitor
        {
        public:
            IPlatformFile& PlatformFile;
    
            FFolderVisitor(IPlatformFile& InPlatformFile) :
                PlatformFile(InPlatformFile), RootNode(nullptr), PreviousNode(nullptr),
                FolderDepth(-1), PreviousDepth(-1) {};
    
            FFolderNode *CreateRootNode(const FString& Path, const FString& Name)
            {
                VisitedNodes.Empty();
                if (RootNode != nullptr)
                    delete RootNode; // TODO: Traverse entire tree, releasing memory for all child nodes
    
                TArray<FString> SubPath;
                Path.ParseIntoArray(SubPath, TEXT("/"));
                if (SubPath.Num() > 0 && SubPath[SubPath.Num() - 1] == Name)
                    SubPath.RemoveAt(SubPath.Num() - 1);
    
                return RootNode = new FFolderNode(FString::Join(SubPath, TEXT("/")), Name);
            };
    
            virtual bool Visit(const TCHAR* FilenameOrDirectory, bool bIsDirectory) override
            {
                auto Path = FString(FilenameOrDirectory);
                auto Result = PlatformFile.IterateDirectory(FilenameOrDirectory, *this);
    
                if (RootNode == nullptr)
                    return false;
    
                FFolderNode *ThisNode = nullptr;
                if (VisitedNodes.Num() < 1)
                    ThisNode = RootNode;
                else
                    ThisNode = new FFolderNode();
    
                auto TempPath = Path.Replace(*ContentPath, TEXT(""));
                TArray<FString> PathArray;
                TempPath.ParseIntoArray(PathArray, TEXT("/"));
                FolderDepth = PathArray.Num();
    
                //
                // DO SOMETHING here, even though RootNode is NOT guaranteed
                // to be the actual root of the tree... ?
                //
    
                PreviousNode = ThisNode;
                PreviousDepth = FolderDepth;
                VisitedNodes.Add(ThisNode);
    
                return true;
            };
    
            FORCEINLINE FFolderNode GetRootNode() const {
                if (RootNode == nullptr)
                    return FFolderNode();
                return *RootNode;
            };
    
        private:
            FFolderNode *RootNode;
            FFolderNode *PreviousNode;
            int32 FolderDepth;
            int32 PreviousDepth;
            TArray<FFolderNode*> VisitedNodes;
        };
    
        FFolderVisitor FolderList(FPlatformFileManager::Get().GetPlatformFile());
        auto RootNode = FolderList.CreateRootNode(ContentPath, TEXT("Content"));
        FolderList.PlatformFile.IterateDirectory(*ContentPath, FolderList);
    
        return *RootNode;
    }
    

    如何使用引擎遍历文件结构的方式正确构建链表?

    最佳答案

    IterateDirectory中调用FFolderVisitor::Visit似乎实际上导致了遍历的奇怪顺序。创建单独的方法来处理根节点的初始化并从那里调用IterateDirectory之后,遍历将以正确的DFS顺序进行。

    08-27 02:15