【问题标题】:POSIX Program to search entire file system for a file用于在整个文件系统中搜索文件的 POSIX 程序
【发布时间】:2011-04-28 05:12:07
【问题描述】:

大家好。我需要编写一个 POSIX 程序来在整个文件系统中搜索从顶层目录开始的指定文件。我有一些根本没有完成的代码,但是当我运行它并检查特定文件是否是目录时,它说这个根本不是目录的文件是一个目录并且正在尝试移入其中,导致错误。我不知道我怎么能告诉它这种类型的文件不是目录。

这是我的代码。我知道这并不完美,我可能会在获取目录名称并将它们传递给函数的方式上做一些不同的事情。无论哪种方式,我很确定我必须递归地执行此操作。

有问题的文件是 /dev/dri/card0,我从 Debian 虚拟机运行它。

#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <time.h>
#include <stdint.h>
#include <locale.h>
#include <langinfo.h>
#include <fcntl.h>
#include <iostream>
#include <stdio.h>
#include <string>
using namespace std; 

void SearchDirectory(string file_Name, string directory){
    string new_Directory = directory; 
    DIR *dirp; 
    dirp = opendir(directory.c_str()); 
    struct dirent *dptr; 
    struct stat statStruct; 

    while(dptr = readdir(dirp)){
        stat(dptr->d_name, &statStruct); 
        if( S_ISDIR(statStruct.st_mode) ){

            string check = dptr->d_name; 
            if ( check.compare(".") == 0 || check.compare("..") == 0 ){
                continue; 
            }
            else{
                cout << dptr->d_name << " is is a directory" << endl; 
                new_Directory.append("/");
                new_Directory.append(dptr->d_name);  
                SearchDirectory(file_Name, new_Directory); 
            }
        }
        else if( S_ISREG(statStruct.st_mode)){
            string check = dptr->d_name; 
            if( check.compare(file_Name) == 0){
                cout << "Found " << file_Name << " in " << directory << "/" << endl; 
            }
        }
    }
}

int main(int argc, char *argv[]){

    if(argc < 2 || argc > 2){
        cerr << "This program will find the specified file." << endl; 
        cerr << "Usage: mysearch <filename>" << endl; 
        return 1; 
    }

    string file_Name = argv[1]; 
    SearchDirectory(file_Name, "/"); 

    return 0; 

}

【问题讨论】:

  • 另外,nftw,虽然这是 XSI 而不是 POSIX 基础。
  • @ikegami -- 我不认为他在寻找 card0。我认为他的意思是 /dev/dri/card0 的 S_ISDIR 是真的,但是 opendir("/dev/dri/card0") 失败了。

标签: c++ c posix


【解决方案1】:

POSIX.2 需要一个有效的“查找”命令。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <filename>", argv[0]);
    }

    execlp("find", "find", "/", "-name", argv[1], "-print", (char *)NULL);
    exit(EXIT_FAILURE);
}

【讨论】:

    【解决方案2】:

    -&gt;d_name 只返回文件名,而不是文件路径。您需要统计(尚未构建)new_Directory 而不是 dptr-&gt;d_name

    如果一个目录包含多个子目录,您也会遇到问题。您对new_Directory 的构造对于第一个子目录之后的每个子目录都不正确。

    你从来没有closedir你的目录句柄,所以你的资源用完了。您还应该考虑在递归之前将整个目录加载到一个数组中,以避免句柄用完。

    void SearchDirectory(string directory, string target_File_Name){
        DIR *dirp = opendir(directory.c_str());
        if (!dirp) {
            perror(("opendir " + directory).c_str());
            return;
        }
    
        struct dirent *dptr;
        while(dptr = readdir(dirp)){
            string file_Name = dptr->d_name;
            string file_Path = directory + "/" + file_Name;
    
            struct stat statStruct; 
            stat(file_Path.c_str(), &statStruct); 
            if( S_ISDIR(statStruct.st_mode) ){
                if ( file_Name.compare(".") == 0 || file_Name.compare("..") == 0 ){
                    continue; 
                }
    
                SearchDirectory(file_Path, target_File_Name);
            }
            else if( S_ISREG(statStruct.st_mode)){
                if( file_Name.compare(target_File_Name) == 0){
                    cout << file_Path << endl;
                }
            }
        }
    
        closedir(dirp);
    }
    

    更新:添加第二个问题。

    更新:添加第三个问题。

    更新:添加代码。

    【讨论】:

    • 或者您可以使用fstatat 来避免组装字符串(以及目录结构中相关的竞争条件)。
    【解决方案3】:

    不是为了写“关键是自己想出一种方法”的OP的利益,而是为了后代的利益,这里有一种使用Boost.Filesystem的方法:

    #include <boost/filesystem.hpp>
    namespace fs = boost::filesystem;
    
    // sample usage: find_file("/home", ".profile");
    void find_file( const fs::path& dirPath, const std::string& fileName) {
      fs::recursive_directory_iterator end;
      for(fs::recursive_directory_iterator it(dirPath); it != end; ++it) {
        if(it->leaf() == fileName)
          std::cout << it->path() << "\n";
        if(fs::is_symlink(it->symlink_status()))
          it.no_push();
      }
    }
    

    【讨论】:

      【解决方案4】:

      使用forkexecv 和 Unix 实现的 /usr/bin/find 进程并将其输出重定向到您的结果区域?

      【讨论】:

      • 我不能。关键是自己想出一种方法:P 谢谢。
      【解决方案5】:

      我不确定它是否是 POSIX,但 nftw 库函数在 UNIX(HP-UX、AIX、Linux)上广泛可用。

      【讨论】:

        【解决方案6】:

        您的问题是“在树中搜索匹配”

        BFS 和 DFS 是规范的基本算法。给他们一个起始节点然后去。

        如果你遵循符号链接,你会遇到麻烦;所以测试他们,不要跟随他们。

        您应该能够将 *FS 算法中的每个点映射到目录操作。

        【讨论】:

          【解决方案7】:

          既然 C++ 是一个选项,为什么不使用 Boost.Filesystem 之类的东西呢? Boost.Filesystem two-minute tutorial 给出了如何使用 directory iterators 实现搜索的示例。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-04-04
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多