【问题标题】:How can I get FindFirstFile to sort files如何让 FindFirstFile 对文件进行排序
【发布时间】:2009-03-14 20:31:34
【问题描述】:

我正在使用标准的FindFirstFindNext 来检索目录中的所有文件 但我需要对结果进行排序(与单击资源管理器中的名称列基本上对它们进行排序的顺序相同) 我怎样才能做到这一点 这必须通过 Win32 完成 谢谢

【问题讨论】:

    标签: c++ c winapi


    【解决方案1】:

    您可以为此使用Indexing Service,但我建议您在使用 FindFirstFile 时自行处理排序。

    FindFirstFile Win32 API 无法进行排序。还有一个稍微高级一点的FindFirstFileEx,但即使这样也不允许排序。

    有一个Raymond Chen post on The Old New Thing about FindFirstFile's limitations

    您最好的选择可能是将所有结果加载到一个向量中,然后对其进行排序。

    【讨论】:

      【解决方案2】:

      正如大家所指出的,FindFirstFile() 不会也不能对它返回的文件进行排序。它在相当低的级别上运行,并以与文件系统在目录中的目录条目的自然顺序相关的顺序返回文件。

      在使用 FAT 和 FAT32 格式化的磁盘上,该顺序与文件的创建顺序、文件删除修改顺序以及可能重新使用现在空的目录条目插槽的顺序密切相关。这是因为 FAT 目录(就像在许多 unix 文件系统上一样)只是一个固定大小的目录条目结构的打包数组,以及一个丑陋的 hack,用于将用 Unicode 编写的长文件名放入为用 ASCII 编写的 8.3 名称设计的目录结构中。与 Unix 不同,读取目录条目需要调用 Win32 API,但这不会影响读取条目的顺序。

      在 NTFS(据我所知)上,目录以 B 树的某种变体表示,因此 Win32 API 看到的文件的自然顺序与该数据结构的自然索引有关。

      您可以在命令提示符下查看与DIR 命令的区别。在 FAT32 卷上,DIR 显示文件的顺序与将同一文件夹复制到 NTFS 卷时的顺序不同。 DIR /ON 应该以相同的顺序列出文件,而不管使用的底层文件系统如何。

      当您按名称排序时,DIR 生成的未排序顺序与 Windows 资源管理器生成的顺序相同。 (就此而言,DIR /ON 也不一样。)

      Windows 资源管理器使用与大小写无关的排序,它似乎也忽略了排序中的一些标点符号,并试图巧妙地处理数字。特别是,简单地使用qsort()stricmp() 不会得到与Explorer 相同的答案。目前尚不清楚 Explorer 或 DIR 使用的实际排序顺序是否记录在任何地方。

      例如,以下名称在 DIR 中的排序如下:

      C:\temp\test> dir/on/b
      aoli.txt
      a-one.txt
      atwo.txt
      b1.txt
      b10.txt
      b2.txt
      b-20.txt
      b21.txt
      b3.txt
      b-4.txt
      

      但从资源管理器中转录并在“名称”列中排序,它们的顺序如下:

      aoli.txt
      a-one.txt
      atwo.txt
      b1.txt
      b2.txt
      b3.txt
      b10.txt
      b21.txt
      b-4.txt
      b-20.txt
      

      我很难想象将简单应用在比较函数中以获得后一种效果。

      【讨论】:

        【解决方案3】:

        您可以通过将文件名放入 std::set 来轻松地对文件名进行排序,如下所示:

        std::string FileName;
        std::set<string> ListOfFileNames;
        
        WIN32_FIND_DATAA findFileData;
        HANDLE MyHandle = FindFirstFileA("*.*",&findFileData);
        
        if( MyHandle != INVALID_HANDLE_VALUE)
        {
            FileName = findFileData.cFileName;
            ListOfFileNames.insert(FileName);
        
            while(FindNextFileA(MyHandle,&findFileData) != 0)
            {
                FileName = findFileData.cFileName;
                ListOfFileNames.insert( FileName );
            }
        }
        
        FindClose(MyHandle);
        
        // Output the list of names found
        for(std::set<string>::iterator Name = ListOfFileNames.begin() ; Name != ListOfFileNames.end() ; ++Name)
        {
            cout << *Name << endl;
        }
        

        【讨论】:

        • “buffer”变量从何而来?
        【解决方案4】:

        您需要将所有文件名读入某个合适的集合中,然后自己对它们进行排序。 Windows API 不提供任何排序​​工具。

        【讨论】:

          【解决方案5】:

          Win32

          首先,使用 findfirst 和 findnext 查找所有文件(请记住,findfirst 和 findnext 支持 glob'ing(*.exe 等)...将匹配的文件加载到列表中并对其进行排序。STL 将帮助您在那里。

          Linux

          使用 opendir() 和 readdir() 查找目录中的所有文件。在这些文件上使用 fnmatch() 来进行全局搜索。就像 Windows 一样,将匹配的文件加载到列表中并对其进行排序。

          【讨论】:

          • 在 Linux 上,您可以使用 scandir 进行简单的排序。
          【解决方案6】:

          Windows 确实有针对这种确切情况的 API。例如。你可以使用CompareString,它像资源管理器一样占hyphens/numbering/etc,我相信默认情况下(flags = 0

          【讨论】:

            猜你喜欢
            • 2011-11-08
            • 2019-09-30
            • 1970-01-01
            • 1970-01-01
            • 2014-01-06
            • 1970-01-01
            • 1970-01-01
            • 2017-03-04
            • 2015-05-28
            相关资源
            最近更新 更多