如何在给定文件夹中获取特定扩展名的文件列表?

67

我想获取给定文件夹(包括其子文件夹)中所有特定扩展名的文件名(包括扩展名),而不是完整文件路径。在Python等语言中非常简单,但我对C++中的构造不熟悉。如何实现?


7
boost::filesystem 擅长文件操作。 - chris
1
在 Python 之后写 C++ 肯定感觉就像在 C++ 之后写汇编语言一样 :) 就标准 C++ 而言,这是一个令人惊讶的代码密集型任务。我赞同使用 boost::filesystem 的建议。 - Sergey Kalinichenko
6个回答

76
#define BOOST_FILESYSTEM_VERSION 3
#define BOOST_FILESYSTEM_NO_DEPRECATED 
#include <boost/filesystem.hpp>

namespace fs = boost::filesystem;

/**
 * \brief   Return the filenames of all files that have the specified extension
 *          in the specified directory and all subdirectories.
 */
std::vector<fs::path> get_all(fs::path const & root, std::string const & ext)
{
    std::vector<fs::path> paths;

    if (fs::exists(root) && fs::is_directory(root))
    {
        for (auto const & entry : fs::recursive_directory_iterator(root))
        {
            if (fs::is_regular_file(entry) && entry.path().extension() == ext)
                paths.emplace_back(entry.path().filename());
        }
    }

    return paths;
}             

3
好的,这是一个便携的答案。 - v.oddou
2
对我而言唯一不起作用的是“and”,我将其替换为“&&”。其余部分都非常好。+1 - Jav_Rock
12
注意:对于文件扩展名,不要忘记加上点号......例如“.jpg”是正确的写法,而不是“jpg”。 - Silex
1
代码是 using namespace std;(应该加上)。 - bazz
1
请注意,此代码仅提供文件名(即不带文件的完整路径)。如果您需要完整路径,请删除“ .filename() ”调用。否则,此代码非常好用。谢谢! - rayryeng
显示剩余2条评论

55

一个 C++17 代码

#include <fstream>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    std::string path("/your/dir/");
    std::string ext(".sample");
    for (auto &p : fs::recursive_directory_iterator(path))
    {
        if (p.path().extension() == ext)
            std::cout << p.path().stem().string() << '\n';
    }
    return 0;
}

1
我很惊讶这个解决方案比其他非跨平台、非STL的解决方案还要差!唯一可以改进的是使用std::endl或将“p”变成一个const变量。 - Raleigh L.
5
@RaleighL. “std::endl” 在循环中是一种风险悲观化的做法。默认情况下,“\n”更加正确。 - v.oddou

19

在Windows上,你可以这样做:

void listFiles( const char* path )
{
   struct _finddata_t dirFile;
   long hFile;

   if (( hFile = _findfirst( path, &dirFile )) != -1 )
   {
      do
      {
         if ( !strcmp( dirFile.name, "."   )) continue;
         if ( !strcmp( dirFile.name, ".."  )) continue;
         if ( gIgnoreHidden )
         {
            if ( dirFile.attrib & _A_HIDDEN ) continue;
            if ( dirFile.name[0] == '.' ) continue;
         }

         // dirFile.name is the name of the file. Do whatever string comparison 
         // you want here. Something like:
         if ( strstr( dirFile.name, ".txt" ))
            printf( "found a .txt file: %s", dirFile.name );

      } while ( _findnext( hFile, &dirFile ) == 0 );
      _findclose( hFile );
   }
}

在类Unix系统中,例如Linux或OsX:

void listFiles( const char* path )
{
   DIR* dirFile = opendir( path );
   if ( dirFile ) 
   {
      struct dirent* hFile;
      errno = 0;
      while (( hFile = readdir( dirFile )) != NULL ) 
      {
         if ( !strcmp( hFile->d_name, "."  )) continue;
         if ( !strcmp( hFile->d_name, ".." )) continue;

         // in linux hidden files all start with '.'
         if ( gIgnoreHidden && ( hFile->d_name[0] == '.' )) continue;

         // dirFile.name is the name of the file. Do whatever string comparison 
         // you want here. Something like:
         if ( strstr( hFile->d_name, ".txt" ))
            printf( "found an .txt file: %s", hFile->d_name );
      } 
      closedir( dirFile );
   }
}

你的解决方案会在模式“foo.txt.exe”中找到文件。我不认为它具有 .txt 扩展名。 - Kaz Dragon
在Windows上,您在哪里设置“gIgnoreHidden”的值?它是一个标志吗? - hshantanu
是的 - 在这个例子中,它是一个全局布尔值。但实际上你可以做任何事情 - 比如将它作为另一个参数传递给listFiles。 - Rafael Baptista
在Windows 8(?)及以后的x64版本中,我认为hFile应该是intptr_t而不是long。使用long将导致在调用_findnext时出现问题。 - Kaitain
对于 Posix,opendir、readdir 和 closedir 需要哪些头文件? - Naveen

5
获取文件列表并处理每个文件,遍历它们并将其存储回不同的文件夹中。
void getFilesList(string filePath,string extension, vector<string> & returnFileName)
{
    WIN32_FIND_DATA fileInfo;
    HANDLE hFind;   
    string  fullPath = filePath + extension;
    hFind = FindFirstFile(fullPath.c_str(), &fileInfo);
    if (hFind != INVALID_HANDLE_VALUE){
        returnFileName.push_back(filePath+fileInfo.cFileName);
        while (FindNextFile(hFind, &fileInfo) != 0){
            returnFileName.push_back(filePath+fileInfo.cFileName);
        }
    }
}

使用方法:您可以按照以下方式使用,从文件夹中加载所有文件并逐个循环遍历。

String optfileName ="";        
String inputFolderPath =""; 
String extension = "*.jpg*";
getFilesList(inputFolderPath,extension,filesPaths);
vector<string>::const_iterator it = filesPaths.begin();
while( it != filesPaths.end())
{
    frame = imread(*it);//read file names
        //doyourwork here ( frame );
    sprintf(buf, "%s/Out/%d.jpg", optfileName.c_str(),it->c_str());
    imwrite(buf,frame);   
    it++;
}

从getFilesList返回一个const vector &会不会更好呢? 在你的使用示例中,忘记声明filesPaths了。 - Azeroth2b

2

0
这是我的解决方案(适用于*nix系统):
#include <dirent.h>

bool FindAllFiles(std::string path, std::string type, std::vector<std::string> &FileList){
  DIR *dir;
  struct dirent *ent;
  FileList.clear();

  if ((dir = opendir (path.c_str())) != NULL) {
    //Examine all files in this directory
    while ((ent = readdir (dir)) != NULL) {
      std::string filename = std::string(ent->d_name);
      if(filename.length() > 4){
        std::string ext = filename.substr(filename.size() - 3);
        if(ext == type){
          //store this file if it's correct type
          FileList.push_back(filename);
        }
      }
    }
    closedir (dir);
  } else {
    //Couldn't open dir
    std::cerr << "Could not open directory: " << path << "\n";
    return false;
  }
  return true;
}

显然,将所需的扩展名更改为您喜欢的任何内容。还假定为3个字符类型。


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