使用 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";
}
}
我使用的示例与 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";
}
}