【问题标题】:How to write UNIX file-system "ls -R /" utility using modern C++11/C++14/C+1Z?如何使用现代 C++11/C++14/C+1Z 编写 UNIX 文件系统“ls -R /”实用程序?
【发布时间】:2014-09-04 07:30:58
【问题描述】:

为了学习/理解现代 C++ 的各种概念,我尝试编写类似的程序,如“ls -R /”,它会递归列出子目录。为了实现这一点,我正在使用 future 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级层次结构的方法是什么?

一般来说,当我们需要对“part-whole hierarchies(recursive)”需要建模的类似事物进行建模/设计时,我们应该遵循什么样的方法。我对"composite design pattern" 有点了解,它可以用来模拟这些东西。这种模式可以应用于这个特定的问题吗?如果是,有人可以提供解释/评论吗?

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

【问题讨论】:

  • 没有TR2。 TRs 前段时间被放弃了。现在我们有了技术规范,其中有很多,而且每一个都专注于一个特定的主题。您正在寻找Filesystem TS(目前正在投票中)。
  • 这与任何其他递归文件搜索实现有何不同?
  • 我无法理解这个问题。您是否要求达到一定深度的文件的递归列表,例如 unix 的 find 命令的 -maxdepth 选项?使用第二个 int 参数指示所需的搜索深度,这似乎并不太难,递归调用将减少该参数。
  • @KerrekSB:是的,我正在使用您提到的文件系统 TS。
  • @PeterSchneider:我想使用现代 c++ 实现类似“ls -R inputdirectory”的实用程序。这只是为了理解/应用 C++ 和设计模式的各种概念,而不是替换任何 UNIX 实用程序。我希望你明白我的意图。

标签: c++11 recursion composite boost-filesystem c++17


【解决方案1】:

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

您可以使用基于范围的 for 循环和 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);
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-27
    • 2013-09-10
    • 2012-08-22
    • 1970-01-01
    • 2010-11-07
    • 1970-01-01
    • 2017-04-12
    相关资源
    最近更新 更多