c++ 在两个文件夹中迭代相同数量的文件

eoigrqb6  于 9个月前  发布在  其他
关注(0)|答案(3)|浏览(110)

我是C++的新手,我在做基本的事情时有点挣扎。如果这个问题太愚蠢或者有人问过这个问题,我很抱歉。我试图在StackOverflow上搜索,但没有成功。
我有以下问题:我有两个文件夹,它们的文件数相同,我们把这个数称为N。我想做一个如下的for循环:

for file1 in directory 1 , file2 in directory2: 
   filename_file_folder_1 = get_filename(file1);
   filename_file_folder_2 = get_filename(file2);

字符串
这一定是可能的,因为我知道如何在Python中实现它。因此,我希望C++也允许这样做。然而,我还没有找到解决这个问题的方法。

guicsvcw

guicsvcw1#

#include <filesystem>
using std::filesystem::path;
using std::filesystem::directory_iterator;

template<typename F>
void for_each_pair_of_files_in(path dir_a, path dir_b, F f)
{
    using Iter = directory_iterator;
    auto it_a = Iter{dir_a};
    auto it_b = Iter{dir_b};

    for (; it_a != Iter{} && it_b != Iter{}; ++it_a, ++it_b)
        f(*it_a, *it_b);
}

void some_compare(path dir_a, path dir_b);

void do_it()
{
    for_each_pair_of_files_in("a/b", "b/c", some_compare);
}

字符串
https://godbolt.org/z/rq8GEMsrd
免责声明:我不知道你到底在做什么,也没有任何保证,这两个迭代器将有一些特定的顺序,所以可能需要一些元素匹配。
在C++20中,有std::ranges::views::zip,相当于Python的zip,但从what I've tried开始,还没有编译器具有此功能。

tvz2xvvm

tvz2xvvm2#

如果你知道这两个目录有相同数量的条目,你可以使用std::filesystem::recursive_directory_iterator来遍历它们(或者如果你不想递归地遍历每个目录,就简单地使用std::filesystem::directory_iterator)。
代码如下:

  • 使用std::transform遍历两个目录,就好像它们是两个范围,并且,对于每次迭代,
  • 从每个目录树中获取一个目录条目,
  • 将两个目录项的路径添加到std::vector;
  • 然后打印矢量。

对于两个输入文件夹树,例如:

/blah1                         
|-- /aaa
|   |-- a1
|-- foo1

/blah2
|-- b1
|-- b2
|-- foo2

字符串
它输出:

[/blah1/aaa, /blah2/b1]
[/blah1/aaa/a1, /blah2/b2]
[/blah1/foo1, /blah2/foo2]
#include <filesystem>
#include <format>
#include <iostream>  // cout
#include <iterator>  // back_inserter
#include <numeric>  // transform
#include <utility>  // pair
#include <vector>

namespace fs = std::filesystem;

int main()
{
    const fs::path path_1{ "/blah1" };
    const fs::path path_2{ "/blah2" };
    std::vector<std::pair<fs::path, fs::path>> v{};
    std::transform(
        fs::recursive_directory_iterator{ path_1 }, {},
        fs::recursive_directory_iterator{ path_2 },
        std::back_inserter(v),
        [](auto& entry1, auto& entry2) {
            return std::pair<fs::path, fs::path>{ entry1.path(), entry2.path() };
        }
    );
    for (auto& p : v)
    {
        std::cout << std::format("[{}, {}]\n",
            p.first.generic_string(), p.second.generic_string());
    }
}

的数据
注意std::recursive_directory_iteratorthe iteration order is unspecified(同样适用于std::directory_iterator)。
如果你需要处理条目的排序列表,我会:

  • 分别浏览每个文件夹,将条目列表保存在std::vector中。
  • 对条目的两个向量进行排序。
  • 然后继续如上所示,同时遍历条目的两个向量。

下面的代码遍历两个文件夹并打印它们的排序条目。它使用 predicate 来过滤要打印的条目(例如,所有条目,或只是普通文件)。

#include <algorithm>  // copy_if, sort
#include <filesystem>
#include <format>
#include <iostream>  // cout
#include <iterator>  // back_inserter, ostream_iterator
#include <numeric>  // transform
#include <vector>

namespace fs = std::filesystem;

template <typename UnaryPredicate>
auto get_entries_sorted_if(const fs::path& path, UnaryPredicate&& pred)
{
    std::vector<fs::path> entries{};
    std::copy_if(fs::recursive_directory_iterator{ path }, {}, std::back_inserter(entries),
        std::forward<UnaryPredicate>(pred));
    std::sort(std::begin(entries), std::end(entries));
    return entries;
}

template <typename UnaryPredicate>
auto print_all_entries_sorted_if(const fs::path& path_1, const fs::path& path_2, UnaryPredicate&& pred) {
    auto entries_1{ get_entries_sorted_if(path_1, std::forward<UnaryPredicate>(pred)) };
    auto entries_2{ get_entries_sorted_if(path_2, std::forward<UnaryPredicate>(pred)) };

    std::transform(std::cbegin(entries_1), std::cend(entries_1),
        std::cbegin(entries_2),
        std::ostream_iterator<std::string>(std::cout),
        [](auto& entry_1, auto& entry_2) {
            return std::format("[{}, {}]\n",
                entry_1.generic_string(), entry_2.generic_string());
        });
};

int main()
{
    const fs::path path_1{ "/blah1" };
    const fs::path path_2{ "/blah2" };

    auto print_all_entries_sorted = [](const fs::path& p1, const fs::path& p2) {
        print_all_entries_sorted_if(p1, p2, [](auto& p) { return true; });
    };
    auto print_all_files_sorted = [](const fs::path& p1, const fs::path& p2) {
        print_all_entries_sorted_if(p1, p2, [](auto& p) { return fs::is_regular_file(p); });
    };

    std::cout << "Printing all entries sorted...\n";
    print_all_entries_sorted(path_1, path_2);
    std::cout << "\nPrinting all files sorted...\n";
    print_all_files_sorted(path_1, path_2);
}

// Outputs:
//
//   Printing all entries sorted...
//   [/blah1/aaa, /blah2/b1]
//   [/blah1/aaa/a1, /blah2/b2]
//   [/blah1/foo1, /blah2/foo2]
//   
//   Printing all files sorted...
//   [/blah1/aaa/a1, /blah2/b1]
//   [/blah1/foo1, /blah2/b2]


请注意,在应用 predicate 之后,条目的数量应该是相同的,而这段代码并没有检查这一点。这就是为什么在打印所有排序的文件时,/blah2/foo2不会显示。如果你用print_all_files_sorted(path_2, path_1)调用这段代码,你会遇到一个问题。这可以通过在std::transform之前进行简单的检查来轻松处理:

if (entries_1.size() != entries_2.size())
    {
        std::cout << "Error: different number of entries.\n";
        return;
    }

a0zr77ik

a0zr77ik3#

我希望这是你正在寻找的:(假设directory 1/2是向量/数组)

for (int i = 0 ; i < N; i++) {
    file1 = directory1[i];
    file2 = directory2[i];
    // can use file1 and file2 however you want now
}

字符串

相关问题