如何从我的C或c++代码中确定目录中的文件列表?
我不允许在程序中执行ls命令并解析结果。
如何从我的C或c++代码中确定目录中的文件列表?
我不允许在程序中执行ls命令并解析结果。
当前回答
为什么不使用glob()?
#include <glob.h>
glob_t glob_result;
glob("/your_directory/*",GLOB_TILDE,NULL,&glob_result);
for(unsigned int i=0; i<glob_result.gl_pathc; ++i){
cout << glob_result.gl_pathv[i] << endl;
}
其他回答
Shreevardhan的设计也适用于遍历子目录:
#include <string>
#include <iostream>
#include <filesystem>
using namespace std;
namespace fs = filesystem;
int main()
{
string path = "\\path\\to\\directory";
// string path = "/path/to/directory";
for (auto & p : fs::recursive_directory_iterator(path))
cout << p.path() << endl;
}
编译:cl /EHsc /W4 /WX /std:c++17 ListFiles.cpp
char **getKeys(char *data_dir, char* tablename, int *num_keys)
{
char** arr = malloc(MAX_RECORDS_PER_TABLE*sizeof(char*));
int i = 0;
for (;i < MAX_RECORDS_PER_TABLE; i++)
arr[i] = malloc( (MAX_KEY_LEN+1) * sizeof(char) );
char *buf = (char *)malloc( (MAX_KEY_LEN+1)*sizeof(char) );
snprintf(buf, MAX_KEY_LEN+1, "%s/%s", data_dir, tablename);
DIR* tableDir = opendir(buf);
struct dirent* getInfo;
readdir(tableDir); // ignore '.'
readdir(tableDir); // ignore '..'
i = 0;
while(1)
{
getInfo = readdir(tableDir);
if (getInfo == 0)
break;
strcpy(arr[i++], getInfo->d_name);
}
*(num_keys) = i;
return arr;
}
不幸的是,c++标准并没有定义这样处理文件和文件夹的标准方法。
由于没有跨平台的方法,最好的跨平台方法是使用boost文件系统模块之类的库。
跨平台提升方法:
The following function, given a directory path and a file name, recursively searches the directory and its sub-directories for the file name, returning a bool, and if successful, the path to the file that was found. 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->leaf() == file_name) // see below { path_found = itr->path(); return true; } } return false; }
来源来自上面提到的boost页面。
对于Unix/Linux系统:
您可以使用opendir / readdir / closedir。
在目录中搜索条目“name”的示例代码如下: Len = strlen(name); Dirp = opendir("."); ((dp = readdir(dirp)) != NULL) 如果(dp - > d_namlen = = len & & !比较字符串(dp - > d_name,名字)){ (空白)closedir (dirp); 返回发现; } (空白)closedir (dirp); 返回NOT_FOUND;
来自上述手册页的源代码。
对于基于windows的系统:
你可以使用Win32 API的FindFirstFile / FindNextFile / FindClose函数。
The following C++ example shows you a minimal use of FindFirstFile. #include <windows.h> #include <tchar.h> #include <stdio.h> void _tmain(int argc, TCHAR *argv[]) { WIN32_FIND_DATA FindFileData; HANDLE hFind; if( argc != 2 ) { _tprintf(TEXT("Usage: %s [target_file]\n"), argv[0]); return; } _tprintf (TEXT("Target file is %s\n"), argv[1]); hFind = FindFirstFile(argv[1], &FindFileData); if (hFind == INVALID_HANDLE_VALUE) { printf ("FindFirstFile failed (%d)\n", GetLastError()); return; } else { _tprintf (TEXT("The first file found is %s\n"), FindFileData.cFileName); FindClose(hFind); } }
来自上述msdn页面的源代码。
这是我想分享的一些东西,谢谢你们的阅读材料。稍微摆弄一下这个函数来理解它。你可能会喜欢的。E表示扩展,p表示路径,s表示路径分隔符。
如果传递路径时没有结束分隔符,则将在路径后附加分隔符。对于扩展名,如果输入的是空字符串,则函数将返回名称中没有扩展名的任何文件。如果只输入一个星号,则将返回目录中的所有文件。如果e的长度大于0,但不是一个*,那么如果e在0点位置没有包含一个点,则会在e前面加上一个点。
对于返回值。如果返回一个零长度的映射,则什么也没有找到,但是目录是打开的。如果返回值中索引999是可用的,但映射大小只有1,那么这意味着打开目录路径有问题。
注意,为了提高效率,这个函数可以分成3个更小的函数。在此基础上,您可以创建一个调用方函数,该函数将根据输入检测将要调用的函数。为什么这样更有效率?也就是说,如果你要抓取所有属于文件的东西,执行那个方法这个为抓取所有文件而构建的子函数只会抓取所有属于文件的东西而不需要在每次找到一个文件时评估任何其他不必要的条件。
这也适用于抓取没有扩展名的文件。为此目的构建的特定函数只在找到的对象是一个文件时计算天气,然后计算文件名称中是否有点。
如果只读取文件不多的目录,节省的时间可能不多。但是,如果您正在读取大量的目录,或者如果目录有数十万个文件,这可能是一个巨大的节省。
#include <stdio.h>
#include <sys/stat.h>
#include <iostream>
#include <dirent.h>
#include <map>
std::map<int, std::string> getFile(std::string p, std::string e = "", unsigned char s = '/'){
if ( p.size() > 0 ){
if (p.back() != s) p += s;
}
if ( e.size() > 0 ){
if ( e.at(0) != '.' && !(e.size() == 1 && e.at(0) == '*') ) e = "." + e;
}
DIR *dir;
struct dirent *ent;
struct stat sb;
std::map<int, std::string> r = {{999, "FAILED"}};
std::string temp;
int f = 0;
bool fd;
if ( (dir = opendir(p.c_str())) != NULL ){
r.erase (999);
while ((ent = readdir (dir)) != NULL){
temp = ent->d_name;
fd = temp.find(".") != std::string::npos? true : false;
temp = p + temp;
if (stat(temp.c_str(), &sb) == 0 && S_ISREG(sb.st_mode)){
if ( e.size() == 1 && e.at(0) == '*' ){
r[f] = temp;
f++;
} else {
if (e.size() == 0){
if ( fd == false ){
r[f] = temp;
f++;
}
continue;
}
if (e.size() > temp.size()) continue;
if ( temp.substr(temp.size() - e.size()) == e ){
r[f] = temp;
f++;
}
}
}
}
closedir(dir);
return r;
} else {
return r;
}
}
void printMap(auto &m){
for (const auto &p : m) {
std::cout << "m[" << p.first << "] = " << p.second << std::endl;
}
}
int main(){
std::map<int, std::string> k = getFile("./", "");
printMap(k);
return 0;
}
Shreevardhan的答案很有效。但是如果你想在c++14中使用它,只需要更改命名空间fs = experimental::filesystem;
也就是说,
#include <string>
#include <iostream>
#include <filesystem>
using namespace std;
namespace fs = experimental::filesystem;
int main()
{
string path = "C:\\splits\\";
for (auto & p : fs::directory_iterator(path))
cout << p << endl;
int n;
cin >> n;
}