1

为了学习/理解现代 C++ 的各种概念,我尝试编写类似的程序,如“ls -R /”,它会递归地列出子目录。为了实现这一点,我正在使用未来的 C++ TS 文件系统库,以便该程序可以移植。到目前为止,我能够编写以下程序来实现这一点。

#include<filesystem>
//Other herader files
// Below typedef is for VS2013
using fspath        = std::tr2::sys::path;
using dir_iterator  = std::tr2::sys::directory_iterator;
using namespace std::tr2::sys;

struct directory {
    std::vector<fspath> files;
    std::vector<fspath> operator()(const fspath& input) {
        std::cout << "Input Directory Name: " << input.string() << std::endl;
        dir_iterator bgnitr(input);
        dir_iterator enditr;
        for (dir_iterator itr = bgnitr; itr != enditr; ++itr) {
            // Only store the directory from input directory, 
            // otherwise display the name
            fspath tmp = *itr;
            if (is_directory(tmp)) {
                files.push_back(tmp);
            }
            else {
                tmp = tmp.filename();
                std::cout << tmp.string() << std::endl;
            }
        }
        return files;
    }
};

int main(int argc, const char** argv) {
    fspath input{argv[1]};
    directory dir;
    auto files = dir(input);
    std::sort(std::begin(files), std::end(files));
    std::for_each(std::begin(files), std::end(files), directory());
    return 0;
}

如果我的输入目录具有一级子目录,则上述程序可以正常工作并产生预期结果。我本可以使用"recursive_directory_iterator",但它给出了输入目录内所有目录中所有文件的列表。

它不处理实际输入目录包含子目录的情况,该子目录本身包含子目录和文件。基本上,这些级别可以达到由 UNIX“ls -R”实用程序处理的任何级别。

问题

我想知道下一个处理目录中n 级层次结构的方法是什么?

一般来说,当我们需要对“部分整体层次结构(递归) ”需要建模的类似事物进行建模/设计时,我们应该遵循什么样的方法。我对可用于对此类东西建模的“复合设计模式”有点了解。这种模式可以应用于这个特定的问题吗?如果是,有人可以提供解释/评论吗?

我在这里的主要目的是了解使用现代 C++ 概念/库/设计概念处理此类问题的一般准则。如果有人需要有关此信息的任何信息,请告诉我。

4

1 回答 1

1

我会重命名你的directory类,它不为目录建模,它是一个打印目录内容的函数。

您可以将基于范围的for循环与 a 一起使用directory_iterator以使语法更简单:

for (auto f : fs::directory_iterator{dir})

您的程序假定它只会使用引用目录的单个参数调用,而ls -R可以使用零个或多个文件或目录参数调用它。

我会这样做,尽管这可能会被改进以简化逻辑main并将其合并到ls函数中:

#include <utility>
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
#include <experimental/filesystem>

namespace fs = std::experimental::filesystem;

void ls(std::ostream& out, const fs::path& dir)
{
  std::vector<std::pair<std::string, bool>> files;
  for (auto f : fs::directory_iterator{dir})
    files.emplace_back(f.path().filename(), is_directory(f));
  std::sort(files.begin(), files.end());

  // print directory contents
  out << dir.string() << ":\n";
  for (auto& f : files)
    out << f.first << '\n';
  out << std::endl;

  // recurse into directories
  for (auto& f : files)
    if (f.second)
      ls(out, dir / f.first);
}

int main(int argc, char** argv)
{
  if (argc < 2)
    ls(std::cout, ".");
  else
  {
    std::vector<std::string> files;
    std::vector<std::string> dirs;
    for (int i = 1; i < argc; ++i)
      if (fs::is_directory(argv[i]))
        dirs.push_back(argv[i]);
      else
        files.push_back(argv[i]);
    std::sort(files.begin(), files.end());
    for (auto& f : files)
      std::cout << f << '\n';
    std::cout << '\n';
    std::sort(dirs.begin(), dirs.end());
    for (auto& d : dirs)
      ls(std::cout, d);
  }
}
于 2014-09-04T10:15:54.387 回答