使用Boost库在目录及其子目录中搜索文件(C++)

4

我希望创建一个应用程序,使用C++的boost库在目录及其子目录中搜索文件。我不想遇到像阿拉伯文件名这样的UNICODE文件的麻烦。那么我该怎么办呢?

更新:

#include <iostream>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/fstream.hpp>
#define BOOST_FILESYSTEM_NO_DEPRECATED
using namespace boost::filesystem;
using namespace std;

bool find_file( const path & dir_path,         // in this directory,
                const std::string & file_name, // search for this name,
                path & path_found )            // placing path here if found
{
  if ( !exists( dir_path ) ) return false;
  directory_iterator end_itr; // default construction yields past-the-end
  for ( directory_iterator itr( dir_path );
        itr != end_itr;
        ++itr )
  {
    if ( is_directory(itr->status()) )
    {
      if ( find_file( itr->path(), file_name, path_found ) ) return true;
    }
    else if ( itr->path().filename() == file_name ) // see below
    {
      path_found = itr->path();
      return true;
    }
  }
  return false;
}

int main()
{
    path myPath = "C:";
    string myFile = ".doc";
    path myfound = "c:";

    find_file(myPath, myFile, myfound);
}

我尝试了这段代码,但它无法编译,显示了许多错误。

undefined reference to `boost::filesystem3::path::filename() const

还有:

X:\mingw\boost\boost_1_47_0\boost\system\error_code.hpp|214|undefined reference to `boost::system::generic_category()'|

我尝试了上面的代码,但徒劳无功。我使用的是CodeBlocks和Boost 1_47_0。 - pourjour
那不是编译器错误,而是链接器错误。 - ildjarn
我尝试了上面的代码,但徒劳无功。 - pourjour
1个回答

10

你需要链接boost_system和boost_filesystem库。如何操作取决于你的编译器/链接器组合;例如,在我的系统上,我必须添加标志-lboost_system-mt -lboost_filesystem-mt

一些注意事项:在Windows上,你通常想要使用wstring(或其他“宽字符”对象)以增加使用Unicode路径的机会。其次,你可以使用find_ifrecursive_directory_iterator使代码更短:

#include <algorithm>
#include <iostream>

#define BOOST_FILESYSTEM_NO_DEPRECATED
#define BOOST_FILESYSTEM_VERSION 3

#include <boost/filesystem.hpp>

using namespace std;
using namespace boost::filesystem;

bool find_file(const path& dir_path, const path& file_name, path& path_found) {
  const recursive_directory_iterator end;
  const auto it = find_if(recursive_directory_iterator(dir_path), end,
                          [&file_name](const directory_entry& e) {
                            return e.path().filename() == file_name;
                          });
  if (it == end) {
    return false;
  } else {
    path_found = it->path();
    return true;
  }
}

int main() {
  const path myPath = L"/usr/local";
  const path myFile = L"filesystem.hpp";
  path myFound;
  find_file(myPath, myFile, myFound);
  wcout << myFound << endl;
}

我的例子使用了C++11的特性autolambda,这些特性在GCC 4.6中提供。如果你的编译器不支持这些特性,你可以用谓词对象替换lambda表达式,用显式类型说明符替换auto

#include <functional>

class file_name_equal: public unary_function<path, bool> {
public:
  explicit file_name_equal(const path& fname): file_name(fname) { }

  bool operator()(const directory_entry& entry) const {
    return entry.path().filename() == file_name;
  }

private:
  path file_name;
};

bool find_file_cxx03(const path& dir_path, const path& file_name,
                     path& path_found) {
  const recursive_directory_iterator end;
  const recursive_directory_iterator it =
    find_if(recursive_directory_iterator(dir_path), end,
            file_name_equal(file_name));
  if (it == end) {
    return false;
  } else {
    path_found = it->path();
    return true;
  }
}

使用Boost.Optional可以消除返回值引用的另一个不错的变体:

...
#include <boost/optional.hpp>

using namespace std;
using namespace boost;
using namespace boost::filesystem;

optional<path> find_file(const path& dir_path, const path& file_name) {
  const recursive_directory_iterator end;
  const auto it = find_if(recursive_directory_iterator(dir_path), end,
                          [&file_name](const directory_entry& e) {
                            return e.path().filename() == file_name;
                          });
  return it == end ? optional<path>() : it->path();
}

int main() {
  const path myPath = L"/usr/local";
  const path myFile = L"filesystem.hpp";
  wcout << find_file(myPath, myFile).get_value_or("not found") << endl;
}

还有,我该如何替换Lambda特性? - pourjour
还有,我该如何替换Lambda特性? - pourjour
第二段代码展示了如何使用谓词对象替换lambda表达式。 - Philipp
在该对象的 operator() 中,您可以放入任何想要的测试,例如对 e.path().extension() 进行测试。 - Philipp
我还没有学习C++11,我没有GCC 4.6版本,我有4.4版本,所以我想要一个简单的代码,可以显示所有具有.doc和.docx扩展名的文件路径,我不需要其他麻烦的新C++内容。 - pourjour
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接