哪些STL容器(S)/算法(S)我可以用它来解决这个问题?可以用、它来、解决这个问题、算法

2023-09-11 06:53:07 作者:花無聲淚無痕

我有一个MFC项目当中,给出一个初始根路径,通过每一个文件,文件夹和子文件夹,随后遍历显示每个文件列表控件的用户。因为这可以很容易成为一个相当冗长的操作,我偶尔产生控制​​到操作系统(经由处理单个消息泵队列),允许每个发现迄今要显示的元素。现在,这里是棘手的部分...

我想保持排序的最后为人所知的修改时间戳记,这(我相信)的元素都需要某种形式的插入排序技术。由于一些元素可以包含重复的时间戳,但不同的文件路径,我们将通过时间戳进行排序(如 MM:DD:YY HH:MM ),一个简单的的std ::矢量似乎并没有做的工作。另外,我preFER不保持用户等待整个操作开始元素进行排序之前完成,因为等待时间的量是未知的,像我如上所述,可以很容易地变得足够冗长进行任何人不耐烦了。

最后,我需要一些方法来保持插入到列表控件同样映射到容器上的排序操作的元素,让用户可以看到在现实的根路径的最近一次修改的内容(和subcontents)时间。

什么是正确的容器(S)和算法(S),以实现这一目标?使用 这基本上就是我现在做的:

 无效CFileSearchDlg :: UpdateDirectoryList(标准::字符串strRootPath)
{
    CFilesystem FS;它采用C ++ 11所述//辅助类;文件系统>遍历文件路径条目
    DWORD时间=的GetTickCount(); //确定是否要在一定的时间周期之后得到控制到OS
    m_listView.DeleteAllItems(); //清除从列表视图控件当前所有元素

    / *
    // CFilesystem ::搜索()接受一个根路径和一个lambda EX pression,并执行前pression每个
    //根路径中找到,传递basic_directory_entry&LT元素;路径>作为参数的拉姆达
    // EX pression,将继续解析,直到没有任何条目被留下(或直到我们返回false)...
    * /
    fs.Search(strRootPath,[和放大器;(CFilesystem :: path_entry PE)
        {
            //这主要是一个统一code项目,所以我们需要将搜索结果转换为一个std :: wstring的
            标准::字符串路径= pe.path()字符串()。
            的std :: wstring的wpath;
            wpath.assign(path.begin(),path.end());

            //获取一个Win32句柄文件/文件夹,或显示错误和放大器;出口
            汽车HFILE = CreateFileA的(path.c_str(),GENERIC_READ,NULL,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
            如果(HFILE == INVALID_HANDLE_VALUE){
                MessageBoxA(NULL,无法打开文件,path.c_str(),MB_OK | MB_ICONERROR);
                返回false; //停止解析
            }

            //获取日期和放大器;文件/文件夹的时间属性,或显示错误和放大器;出口
            TCHAR FILETIME [MAX_PATH];
            ZeroMemory(安培; FILETIME,的sizeof(TCHAR)* MAX_PATH);
            汽车RET = GetLastWriteTime(HFILE,FILETIME,MAX_PATH);
            CloseHandle的(HFILE);
            如果(!RET){
                MessageBoxA(NULL,无法取得日期和放大器;时间属性,path.c_str(),MB_OK | MB_ICONERROR);
                返回false; //停止解析
            }
            的std :: wstring的strTime(FILETIME);

            / ******************* *
            //这是神奇的是应该发生//
            / ******************* /
            InsertPathItem(m_listView,wpath,strTime); // ...怎么会呢?

            //检查是否我们应该得到控制的操作系统
            自动剔=的GetTickCount();
            如果(打勾 - 时间> 100){
                YieldControl();
                时间=打勾;
            }

            //继续解析目录内容
            返回true;
        }
    );
}
 

  

修改的:   充分答案似乎是galinette的(有关正确STL容器),和foraidt的组合(有关同步的数据的视图)。

解决方案

只需使用的std :: multimap中,与主要类型是整数的时间戳(最快的方法),或者如你所说时间字符串如果默认字符串排序保持时间戳顺序(这是慢)

 的std :: multimap中< time_t的,的std :: wstring的>
 

 的std :: multimap中<的std ::字符串的std :: wstring的>
 
STL系列 ,stack和queue详解,掌握STL容器从现在开始

与插入:

  myFileMap.insert(标准::对< time_t的,的std :: wstring的>(时间,wPath));
 

I have an MFC project which, given an initial root path, iterates through every file, folder and subfolder, and subsequently displays each file to the user in a List Control. Since this can easily become a rather lengthy operation, I occasionally yield control to the operating system (via processing a single message pump queue), allowing each of the elements discovered thus far to be displayed. Now here comes the tricky part...

I would like to keep the elements sorted by their last known modification timestamps, which (I believe) would require some kind of insertion sorting technique. Since some elements may contain duplicate timestamps, but different file paths, and we would be sorting by timestamp (stored as an std::string in the format of MM:DD:YY hh:mm), a simple std::vector doesn't appear to do the job. Also, I would prefer to not keep the user waiting for the entire operation to complete before starting to sort the elements, since the amount of time to wait is unknown and like I stated above, could easily become lengthy enough to make any person impatient.

Lastly, I would need some way to keep the elements inserted into the List Control equally mapped to the sorting operations on the container, so the user can see the most recently modified contents (and subcontents) of the root path in real-time.

What would be the proper container(s) and algorithm(s) to use in order to achieve this? Here's basically what I'm doing now:

void CFileSearchDlg::UpdateDirectoryList(std::string strRootPath)
{
    CFilesystem fs; // Helper class which uses C++11 <filesystem> to iterate through file path entries
    DWORD time = GetTickCount(); // Determines if we should yield control to the OS after a certain period of time
    m_listView.DeleteAllItems(); // Clears all current elements from the list view control

    /*
    // CFilesystem::Search() takes in a root path and a lambda expression, and executes the expression for each
    // element found within the root path, passing a basic_directory_entry<path> as a parameter to the lambda
    // expression, and will continue to parse until no entries are left (or until we return false)...
    */
    fs.Search(strRootPath, [&](CFilesystem::path_entry pe)
        {
            // This is primarily a Unicode project, so we need to convert the search results to an std::wstring
            std::string path = pe.path().string();
            std::wstring wpath;
            wpath.assign(path.begin(), path.end());

            // Get a Win32 handle to the file/folder, or display an error & exit
            auto hFile = CreateFileA(path.c_str(), GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
            if (hFile == INVALID_HANDLE_VALUE) {
                MessageBoxA(NULL, "Failed to open file", path.c_str(), MB_OK | MB_ICONERROR);
                return false; // Stop parsing
            }

            // Get the date & time attributes of the file/folder, or display an error & exit
            TCHAR fileTime[MAX_PATH];
            ZeroMemory(&fileTime, sizeof(TCHAR)* MAX_PATH);
            auto ret = GetLastWriteTime(hFile, fileTime, MAX_PATH);
            CloseHandle(hFile);
            if (!ret) {
                MessageBoxA(NULL, "Failed to get date & time attributes", path.c_str(), MB_OK | MB_ICONERROR);
                return false; // Stop parsing
            }
            std::wstring strTime(fileTime);

            /************************************************** 
            // THIS IS WHERE THE MAGIC IS SUPPOSED TO HAPPEN //
            /*************************************************/
            InsertPathItem(m_listView, wpath, strTime); // ... But how?

            // Check if we should yield control to the operating system
            auto tick = GetTickCount();
            if (tick - time > 100) {
                YieldControl();
                time = tick;
            }

            // Continue to parse directory contents
            return true;
        }
    );
}

EDIT: The full answer appears to be a combination of galinette's (about the proper STL container), and foraidt's (about synchronizing the view with the data).

解决方案

Just use a std::multimap, with the key type either an integer timestamp (the fastest way) or as you suggested a time string if the default string sort keeps the timestamp order (this is slower)

std::multimap<time_t, std::wstring>

or

std::multimap<std::string, std::wstring>

Insert with:

myFileMap.insert(std::pair<time_t, std::wstring>(time,wPath));