使用 boost::filesystem 对目录的子文件夹和文件名进行数字排序

Sort subfolders and filenames of a directory numerically using boost::filesystem

我使用的示例与 boost tutorials 中的示例相同。但是因为我的文件名是编号的(1,20,23,..)。该代码无法比较字符串(例如 20 < 7)。有没有办法在数字上比较 directory_iteration 。这是代码片段

else if (is_directory(p))      // is p a directory?
      {
        cout << p << " is a directory containing:\n";

        typedef vector<path> vec;             // store paths,
        vec v;                                // so we can sort them later

        copy(directory_iterator(p), directory_iterator(), back_inserter(v));

        sort(v.begin(), v.end());             //  **I want to sort this numerically**

        for (vec::const_iterator it(v.begin()), it_end(v.end()); it != it_end; ++it)
        {
          cout << "   " << *it << '\n';
        }
      }

目录和子文件夹的布局如下所示:

root/
    1/
     1.bmp
     2.bmp
     3.bmp
     4.bmp
     ...
    2/
     1.bmp
     2.bmp
     3.bmp
     4.bmp
    ....
    3/
     1.bmp
     2.bmp
     3.bmp
     4.bmp
     ....

由于您无法将文件名的格式更改为可排序,因此您需要自己进行一些处理——解析每个文件名中的数字,并将其用于排序。

我想到了两种方法,在内存和 CPU 使用之间进行权衡。

方法一:

存储文件名和数值对,填充向量时解析。

方法二:

仅存储路径并在比较期间执行转换。


代码:

#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <iostream>

namespace fs = boost::filesystem;

int parse_filename(fs::path const& p)
{
    return std::stoi(p.filename().string());
}

void sort_numeric_1(fs::path const& p)
{
    typedef std::pair<fs::path, int> file_entry;
    typedef std::vector<file_entry> vec;
    vec v;

    for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it) {
        v.emplace_back(*it, parse_filename(*it));
    }

    std::sort(v.begin(), v.end()
        , [](file_entry const& a, file_entry const& b) {
        return a.second < b.second;
    });

    for (vec::const_iterator it(v.begin()), it_end(v.end()); it != it_end; ++it) {
        std::cout << "   " << it->first << '\n';
    }
}

void sort_numeric_2(fs::path const& p)
{
    typedef std::vector<fs::path> vec;
    vec v;

    std::copy(fs::directory_iterator(p), fs::directory_iterator(), back_inserter(v));

    std::sort(v.begin(), v.end()
        , [](fs::path const& a, fs::path const& b) {
        return std::stoi(a.filename().string()) < std::stoi(b.filename().string());
    });

    for (vec::const_iterator it(v.begin()), it_end(v.end()); it != it_end; ++it) {
        std::cout << "   " << *it << '\n';
    }
}

int main()
{
    sort_numeric_1("test");
    std::cout <<"\n";
    sort_numeric_2("test");
}

目录内容:

> ls test
1.txt  10.txt  127.txt  20.txt  23.txt

输出:

"test.txt"
"test.txt"
"test.txt"
"test.txt"
"test7.txt"

"test.txt"
"test.txt"
"test.txt"
"test.txt"
"test7.txt"

更新它以处理您显示的整个目录结构,您可能会得到这样的结果:

  • 先找到所有的目录,按数字排序
  • 然后对找到的每个目录中的文件进行排序
  • 合并所有排序的文件列表

示例:

#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <iostream>

namespace fs = boost::filesystem;

typedef std::vector<fs::path> path_vec;

void sort_numeric(path_vec& v)
{
    std::sort(v.begin(), v.end()
        , [](fs::path const& a, fs::path const& b) {
        return std::stoi(a.filename().string()) < std::stoi(b.filename().string());
    });
}

path_vec sort_root_dir(fs::path const& p)
{
    path_vec dirs;

    for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it) {
        if (is_directory(*it)) {
            dirs.emplace_back(*it);
        }
    }

    sort_numeric(dirs);

    path_vec files;
    for (path_vec::const_iterator it(dirs.begin()), it_end(dirs.end()); it != it_end; ++it) {
        path_vec dir_files;
        std::copy(fs::directory_iterator(*it), fs::directory_iterator(), back_inserter(dir_files));
        sort_numeric(dir_files);
        files.insert(files.end(), dir_files.begin(), dir_files.end());
    }

    return files;
}

int main()
{
    path_vec files = sort_root_dir("test");

    for (auto const& f : files) {
        std::cout << f << "\n";
    }
}