Làm cách nào tôi có thể xác định danh sách các tệp trong một thư mục từ bên trong mã C hoặc C ++ của mình?
Tôi không được phép thực thi ls
lệnh và phân tích kết quả từ trong chương trình của mình.
Làm cách nào tôi có thể xác định danh sách các tệp trong một thư mục từ bên trong mã C hoặc C ++ của mình?
Tôi không được phép thực thi ls
lệnh và phân tích kết quả từ trong chương trình của mình.
Câu trả lời:
Trong các tác vụ nhỏ và đơn giản tôi không sử dụng boost, tôi sử dụng dirent.h cũng có sẵn cho windows:
DIR *dir;
struct dirent *ent;
if ((dir = opendir ("c:\\src\\")) != NULL) {
/* print all the files and directories within directory */
while ((ent = readdir (dir)) != NULL) {
printf ("%s\n", ent->d_name);
}
closedir (dir);
} else {
/* could not open directory */
perror ("");
return EXIT_FAILURE;
}
Nó chỉ là một tệp tiêu đề nhỏ và thực hiện hầu hết những thứ đơn giản mà bạn cần mà không cần sử dụng một cách tiếp cận dựa trên mẫu lớn như boost (không vi phạm, tôi thích boost!).
Tác giả của lớp tương thích windows là Toni Ronkko. Trong Unix, nó là một tiêu đề tiêu chuẩn.
CẬP NHẬT 2017 :
Trong C ++ 17 hiện có một cách chính thức để liệt kê các tệp của hệ thống tệp của bạn : std::filesystem
. Có một câu trả lời tuyệt vời từ Shreevardhan dưới đây với mã nguồn này:
#include <string>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
std::string path = "/path/to/directory";
for (const auto & entry : fs::directory_iterator(path))
std::cout << entry.path() << std::endl;
}
std::experimental::filesystem
, với C ++ 17 thì có std::filesystem
. Xem câu trả lời của Shreevardhan dưới đây. Vì vậy, không cần thư viện bên thứ 3.
C ++ 17 hiện có một std::filesystem::directory_iterator
, có thể được sử dụng như
#include <string>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
std::string path = "/path/to/directory";
for (const auto & entry : fs::directory_iterator(path))
std::cout << entry.path() << std::endl;
}
Ngoài ra, std::filesystem::recursive_directory_iterator
có thể lặp lại các thư mục con là tốt.
namespace fs = std::experimental::filesystem;
. Có vẻ như làm việc ok mặc dù.
std::filesystem::path
đến std::cout
, các dấu ngoặc kép được bao gồm trong đầu ra. Để tránh điều đó, hãy thêm .string()
vào đường dẫn để thực hiện một thay đổi rõ ràng thay vì chuyển đổi ngầm định (ở đây std::cout << p.string() << std::endl;
). Ví dụ: coliru.stacked-crooking.com/view?id=a55ea60bbd36a8a3
std::wstring
được sử dụng hoặc loại từ iterator?
-lstdc++fs
, tôi sẽ nhận được một SIGSEGV (Address boundary error)
. Tôi không thể tìm thấy bất cứ nơi nào trong tài liệu rằng điều này là bắt buộc và trình liên kết cũng không đưa ra bất kỳ manh mối nào. Điều này làm việc cho cả hai g++ 8.3.0
và clang 8.0.0-3
. Có ai có cái nhìn sâu sắc là nơi những thứ như thế này được chỉ định trong tài liệu / thông số kỹ thuật không?
Thật không may, tiêu chuẩn C ++ không định nghĩa một cách làm việc tiêu chuẩn với các tệp và thư mục theo cách này.
Vì không có cách đa nền tảng, nên cách đa nền tảng tốt nhất là sử dụng một thư viện như mô-đun hệ thống tập tin boost .
Phương pháp tăng cường đa nền tảng:
Hàm sau, được cung cấp một đường dẫn thư mục và tên tệp, tìm kiếm đệ quy thư mục và thư mục con của nó cho tên tệp, trả về một bool và nếu thành công, đường dẫn đến tệp được tìm thấy.
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; }
Nguồn từ trang boost được đề cập ở trên.
Đối với các hệ thống dựa trên Unix / Linux:
Bạn có thể sử dụng opendir / readdir / closir .
Mã mẫu tìm kiếm một thư mục để nhập `` name '' là:
len = strlen(name); dirp = opendir("."); while ((dp = readdir(dirp)) != NULL) if (dp->d_namlen == len && !strcmp(dp->d_name, name)) { (void)closedir(dirp); return FOUND; } (void)closedir(dirp); return NOT_FOUND;
Mã nguồn từ các trang người đàn ông ở trên.
Đối với một hệ thống dựa trên windows:
Bạn có thể sử dụng các hàm Win32 API FindFirstFile / FindNextFile / FindClose .
Ví dụ C ++ sau đây cho bạn thấy việc sử dụng tối thiểu 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); } }
Mã nguồn từ các trang msDN ở trên.
FindFirstFile(TEXT("D:\\IMAGE\\MYDIRECTORY\\*"), &findFileData);
std::experimental::filesystem
, với C ++ 17 std::filesystem
, có chức năng tương tự như boost (các lib được lấy từ boost). Xem câu trả lời của Shreevardhan dưới đây.
Một chức năng là đủ, bạn không cần sử dụng bất kỳ thư viện của bên thứ 3 nào (đối với Windows).
#include <Windows.h>
vector<string> get_all_files_names_within_folder(string folder)
{
vector<string> names;
string search_path = folder + "/*.*";
WIN32_FIND_DATA fd;
HANDLE hFind = ::FindFirstFile(search_path.c_str(), &fd);
if(hFind != INVALID_HANDLE_VALUE) {
do {
// read all (real) files in current folder
// , delete '!' read other 2 default folder . and ..
if(! (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
names.push_back(fd.cFileName);
}
}while(::FindNextFile(hFind, &fd));
::FindClose(hFind);
}
return names;
}
PS: như được đề cập bởi @Sebastian, bạn có thể thay đổi *.*
để *.ext
chỉ nhận các tệp EXT (tức là một loại cụ thể) trong thư mục đó.
std::vector<std::wstring>
và sau đó fileName.c_str()
thay vì một chuỗi các chuỗi, sẽ không biên dịch.
Đối với một giải pháp chỉ C, xin vui lòng kiểm tra này. Nó chỉ yêu cầu một tiêu đề phụ:
https://github.com/cxong/tinydir
tinydir_dir dir;
tinydir_open(&dir, "/path/to/dir");
while (dir.has_next)
{
tinydir_file file;
tinydir_readfile(&dir, &file);
printf("%s", file.name);
if (file.is_dir)
{
printf("/");
}
printf("\n");
tinydir_next(&dir);
}
tinydir_close(&dir);
Một số lợi thế so với các tùy chọn khác:
readdir_r
khi có sẵn, có nghĩa là nó (thường)UNICODE
macro tương tựTôi khuyên bạn nên sử dụng glob
với trình bao bọc có thể tái sử dụng này. Nó tạo ra một vector<string>
đường dẫn tệp tương ứng với mẫu hình cầu:
#include <glob.h>
#include <vector>
using std::vector;
vector<string> globVector(const string& pattern){
glob_t glob_result;
glob(pattern.c_str(),GLOB_TILDE,NULL,&glob_result);
vector<string> files;
for(unsigned int i=0;i<glob_result.gl_pathc;++i){
files.push_back(string(glob_result.gl_pathv[i]));
}
globfree(&glob_result);
return files;
}
Mà sau đó có thể được gọi với một mẫu ký tự đại diện hệ thống bình thường, chẳng hạn như:
vector<string> files = globVector("./*");
No such file or directory
. Bạn có thể cho tôi biết làm thế nào để giải quyết vấn đề này xin vui lòng?
GLOB_TILDE
với GLOB_TILDE | GLOB_MARK
và sau đó kiểm tra các đường dẫn kết thúc bằng một dấu gạch chéo. Bạn sẽ phải sửa đổi nó nếu bạn cần.
glob
.
Đây là một mã rất đơn giản trong C++11
việc sử dụng boost::filesystem
thư viện để lấy tên tệp trong một thư mục (không bao gồm tên thư mục):
#include <string>
#include <iostream>
#include <boost/filesystem.hpp>
using namespace std;
using namespace boost::filesystem;
int main()
{
path p("D:/AnyFolder");
for (auto i = directory_iterator(p); i != directory_iterator(); i++)
{
if (!is_directory(i->path())) //we eliminate directories
{
cout << i->path().filename().string() << endl;
}
else
continue;
}
}
Đầu ra giống như:
file1.txt
file2.dat
boost::filesystem
thư viện boost.org/doc/libs/1_58_0/libs/filesystem/doc/index.htm
Tại sao không sử dụng 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;
}
Tôi nghĩ rằng, đoạn dưới đây có thể được sử dụng để liệt kê tất cả các tệp.
#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
static void list_dir(const char *path)
{
struct dirent *entry;
DIR *dir = opendir(path);
if (dir == NULL) {
return;
}
while ((entry = readdir(dir)) != NULL) {
printf("%s\n",entry->d_name);
}
closedir(dir);
}
Sau đây là cấu trúc của dirent struct
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* offset to the next dirent */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file */
char d_name[256]; /* filename */
};
Hãy thử tăng cường cho phương pháp nền tảng x
http://www.boost.org/doc/libs/1_38_0/libs/filesystem/doc/index.htm
hoặc chỉ sử dụng công cụ tập tin cụ thể hệ điều hành của bạn.
Kiểm tra lớp này sử dụng api win32. Chỉ cần xây dựng một thể hiện bằng cách cung cấp foldername
từ đó bạn muốn liệt kê sau đó gọi getNextFile
phương thức để lấy cái tiếp theo filename
từ thư mục. Tôi nghĩ rằng nó cần windows.h
và stdio.h
.
class FileGetter{
WIN32_FIND_DATAA found;
HANDLE hfind;
char folderstar[255];
int chk;
public:
FileGetter(char* folder){
sprintf(folderstar,"%s\\*.*",folder);
hfind = FindFirstFileA(folderstar,&found);
//skip .
FindNextFileA(hfind,&found);
}
int getNextFile(char* fname){
//skips .. when called for the first time
chk=FindNextFileA(hfind,&found);
if (chk)
strcpy(fname, found.cFileName);
return chk;
}
};
Hướng dẫn sử dụng GNU FTW
Ngoài ra, đôi khi thật tốt khi đi thẳng vào nguồn (ý định chơi chữ). Bạn có thể học được rất nhiều bằng cách xem xét các phần bên trong của một số lệnh phổ biến nhất trong Linux. Tôi đã thiết lập một bản sao đơn giản của coreutils GNU trên github (để đọc).
https://github.com/homer6/gnu_coreutils/blob/master/src/ls.c
Có thể điều này không giải quyết được Windows, nhưng một số trường hợp sử dụng các biến thể Unix có thể có bằng các phương pháp này.
Mong rằng sẽ giúp ...
Shreevardhan trả lời hoạt động tuyệt vời. Nhưng nếu bạn muốn sử dụng nó trong c ++ 14, hãy thay đổinamespace fs = experimental::filesystem;
I E,
#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;
}
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;
}
Tôi hy vọng mã này giúp bạn.
#include <windows.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
string wchar_t2string(const wchar_t *wchar)
{
string str = "";
int index = 0;
while(wchar[index] != 0)
{
str += (char)wchar[index];
++index;
}
return str;
}
wchar_t *string2wchar_t(const string &str)
{
wchar_t wchar[260];
int index = 0;
while(index < str.size())
{
wchar[index] = (wchar_t)str[index];
++index;
}
wchar[index] = 0;
return wchar;
}
vector<string> listFilesInDirectory(string directoryName)
{
WIN32_FIND_DATA FindFileData;
wchar_t * FileName = string2wchar_t(directoryName);
HANDLE hFind = FindFirstFile(FileName, &FindFileData);
vector<string> listFileNames;
listFileNames.push_back(wchar_t2string(FindFileData.cFileName));
while (FindNextFile(hFind, &FindFileData))
listFileNames.push_back(wchar_t2string(FindFileData.cFileName));
return listFileNames;
}
void main()
{
vector<string> listFiles;
listFiles = listFilesInDirectory("C:\\*.txt");
for each (string str in listFiles)
cout << str << endl;
}
string2wchar_t
trả về địa chỉ của một biến cục bộ Ngoài ra, có lẽ bạn nên sử dụng các phương thức chuyển đổi có sẵn trong WinAPI thay vì viết các phương thức của riêng bạn.
Việc thực hiện này thực hiện mục đích của bạn, tự động điền vào một chuỗi các chuỗi với nội dung của thư mục được chỉ định.
int exploreDirectory(const char *dirpath, char ***list, int *numItems) {
struct dirent **direntList;
int i;
errno = 0;
if ((*numItems = scandir(dirpath, &direntList, NULL, alphasort)) == -1)
return errno;
if (!((*list) = malloc(sizeof(char *) * (*numItems)))) {
fprintf(stderr, "Error in list allocation for file list: dirpath=%s.\n", dirpath);
exit(EXIT_FAILURE);
}
for (i = 0; i < *numItems; i++) {
(*list)[i] = stringDuplication(direntList[i]->d_name);
}
for (i = 0; i < *numItems; i++) {
free(direntList[i]);
}
free(direntList);
return 0;
}
if
khối đầu tiên . Tôi đang gọi nó vớichar **list; int numItems; exploreDirectory("/folder",list, numItems);
Điều này làm việc cho tôi. Tôi xin lỗi nếu tôi không thể nhớ nguồn. Nó có lẽ là từ một trang người đàn ông.
#include <ftw.h>
int AnalizeDirectoryElement (const char *fpath,
const struct stat *sb,
int tflag,
struct FTW *ftwbuf) {
if (tflag == FTW_F) {
std::string strFileName(fpath);
DoSomethingWith(strFileName);
}
return 0;
}
void WalkDirectoryTree (const char * pchFileName) {
int nFlags = 0;
if (nftw(pchFileName, AnalizeDirectoryElement, 20, nFlags) == -1) {
perror("nftw");
}
}
int main() {
WalkDirectoryTree("some_dir/");
}
bạn có thể nhận được tất cả các tệp trực tiếp trong thư mục gốc của mình bằng cách sử dụng std :: thử nghiệm :: filesystem :: library_iterator (). Sau đó, đọc tên của các pathfiles.
#include <iostream>
#include <filesystem>
#include <string>
#include <direct.h>
using namespace std;
namespace fs = std::experimental::filesystem;
void ShowListFile(string path)
{
for(auto &p: fs::directory_iterator(path)) /*get directory */
cout<<p.path().filename()<<endl; // get file name
}
int main() {
ShowListFile("C:/Users/dell/Pictures/Camera Roll/");
getchar();
return 0;
}
Câu trả lời này sẽ phù hợp với người dùng Windows gặp khó khăn khi làm việc với Visual Studio với bất kỳ câu trả lời nào khác.
Tải xuống tệp dirent.h từ trang github. Nhưng tốt hơn là chỉ sử dụng tệp Raw dirent.h và làm theo các bước của tôi dưới đây (đó là cách tôi làm cho nó hoạt động).
Trang Github cho dirent.h cho Windows: Trang Github cho dirent.h
Raw Dirent File: Raw dirent.h File
Chuyển đến dự án của bạn và Thêm một mục mới ( Ctrl+ Shift+ A). Thêm một tệp tiêu đề (.h) và đặt tên là dirent.h.
Dán mã tệp dirent.h thô vào tiêu đề của bạn.
Bao gồm "dirent.h" trong mã của bạn.
Đặt void filefinder()
phương thức dưới đây vào mã của bạn và gọi nó từ main
hàm của bạn hoặc chỉnh sửa hàm theo cách bạn muốn sử dụng.
#include <stdio.h>
#include <string.h>
#include "dirent.h"
string path = "C:/folder"; //Put a valid path here for folder
void filefinder()
{
DIR *directory = opendir(path.c_str());
struct dirent *direntStruct;
if (directory != NULL) {
while (direntStruct = readdir(directory)) {
printf("File Name: %s\n", direntStruct->d_name); //If you are using <stdio.h>
//std::cout << direntStruct->d_name << std::endl; //If you are using <iostream>
}
}
closedir(directory);
}
Hệ thống gọi nó!
system( "dir /b /s /a-d * > file_names.txt" );
Sau đó chỉ cần đọc các tập tin.
EDIT: Câu trả lời này nên được coi là một hack, nhưng nó thực sự hoạt động (mặc dù theo cách cụ thể của nền tảng) nếu bạn không có quyền truy cập vào các giải pháp thanh lịch hơn.
Do các tệp và thư mục con của một thư mục thường được lưu trữ trong cấu trúc cây, nên một cách trực quan là sử dụng thuật toán DFS để duyệt qua từng đệ quy. Dưới đây là một ví dụ trong hệ điều hành windows bằng cách sử dụng các hàm tệp cơ bản trong io.h. Bạn có thể thay thế các chức năng này trong nền tảng khác. Điều tôi muốn bày tỏ là ý tưởng cơ bản về DFS đáp ứng hoàn hảo vấn đề này.
#include<io.h>
#include<iostream.h>
#include<string>
using namespace std;
void TraverseFilesUsingDFS(const string& folder_path){
_finddata_t file_info;
string any_file_pattern = folder_path + "\\*";
intptr_t handle = _findfirst(any_file_pattern.c_str(),&file_info);
//If folder_path exsist, using any_file_pattern will find at least two files "." and "..",
//of which "." means current dir and ".." means parent dir
if (handle == -1){
cerr << "folder path not exist: " << folder_path << endl;
exit(-1);
}
//iteratively check each file or sub_directory in current folder
do{
string file_name=file_info.name; //from char array to string
//check whtether it is a sub direcotry or a file
if (file_info.attrib & _A_SUBDIR){
if (file_name != "." && file_name != ".."){
string sub_folder_path = folder_path + "\\" + file_name;
TraverseFilesUsingDFS(sub_folder_path);
cout << "a sub_folder path: " << sub_folder_path << endl;
}
}
else
cout << "file name: " << file_name << endl;
} while (_findnext(handle, &file_info) == 0);
//
_findclose(handle);
}
Tôi đã cố gắng làm theo ví dụ được đưa ra trong cả hai câu trả lời và có thể đáng lưu ý rằng nó xuất hiện như thể std::filesystem::directory_entry
đã được thay đổi để không có sự quá tải của <<
toán tử. Thay vì std::cout << p << std::endl;
tôi phải sử dụng những điều sau đây để có thể biên dịch và làm cho nó hoạt động:
#include <iostream>
#include <filesystem>
#include <string>
namespace fs = std::filesystem;
int main() {
std::string path = "/path/to/directory";
for(const auto& p : fs::directory_iterator(path))
std::cout << p.path() << std::endl;
}
cố gắng tự mình vượt qua p
để std::cout <<
dẫn đến một lỗi quá tải bị thiếu.
Dựa trên những gì herohuyongtao đã đăng và một vài bài viết khác:
http://www.cplusplus.com/forum/general/39766/
Loại đầu vào dự kiến của FindFirstFile là gì?
Làm thế nào để chuyển đổi chuỗi thành chuỗi?
Đây là một giải pháp Windows.
Vì tôi muốn truyền vào chuỗi std :: và trả về một vectơ chuỗi, tôi phải thực hiện một vài chuyển đổi.
#include <string>
#include <Windows.h>
#include <vector>
#include <locale>
#include <codecvt>
std::vector<std::string> listFilesInDir(std::string path)
{
std::vector<std::string> names;
//Convert string to wstring
std::wstring search_path = std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(path);
WIN32_FIND_DATA fd;
HANDLE hFind = FindFirstFile(search_path.c_str(), &fd);
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
// read all (real) files in current folder
// , delete '!' read other 2 default folder . and ..
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
//convert from wide char to narrow char array
char ch[260];
char DefChar = ' ';
WideCharToMultiByte(CP_ACP, 0, fd.cFileName, -1, ch, 260, &DefChar, NULL);
names.push_back(ch);
}
}
while (::FindNextFile(hFind, &fd));
::FindClose(hFind);
}
return names;
}
WIN32_FIND_DATAA
, FindFirstFileA
và FindNextFileA
. Sau đó, sẽ không cần phải chuyển đổi kết quả thành multibyte hoặc Input thành unicode.
Chỉ cần một cái gì đó mà tôi muốn chia sẻ và cảm ơn bạn đã đọc tài liệu. Chơi xung quanh với chức năng một chút để hiểu nó. Bạn có thể thích nó. e là viết tắt của phần mở rộng, p là cho đường dẫn và s là cho dấu phân cách đường dẫn.
Nếu đường dẫn được truyền mà không có dấu phân cách kết thúc, dấu phân cách sẽ được thêm vào đường dẫn. Đối với phần mở rộng, nếu một chuỗi rỗng được nhập vào thì hàm sẽ trả về bất kỳ tệp nào không có phần mở rộng trong tên của nó. Nếu một ngôi sao duy nhất được nhập vào, tất cả các tệp trong thư mục sẽ được trả về. Nếu độ dài e lớn hơn 0 nhưng không phải là một dấu * thì dấu chấm sẽ được thêm vào e nếu e không chứa dấu chấm ở vị trí 0.
Đối với một giá trị trả lại. Nếu một bản đồ có độ dài bằng không được trả về thì không tìm thấy gì nhưng thư mục đã mở. Nếu chỉ mục 999 có sẵn từ giá trị trả về nhưng kích thước bản đồ chỉ là 1 thì điều đó có nghĩa là có vấn đề với việc mở đường dẫn thư mục.
Lưu ý rằng để hiệu quả, chức năng này có thể được chia thành 3 chức năng nhỏ hơn. Trên hết, bạn có thể tạo một chức năng người gọi sẽ phát hiện chức năng mà nó sẽ gọi dựa trên đầu vào. Tại sao điều đó hiệu quả hơn? Cho biết nếu bạn định lấy tất cả mọi thứ là một tệp, thực hiện phương thức đó, chức năng con được xây dựng để lấy tất cả các tệp sẽ chỉ lấy tất cả các tệp đó và không cần phải đánh giá bất kỳ điều kiện không cần thiết nào khác mỗi khi tìm thấy tệp.
Điều đó cũng sẽ áp dụng cho khi bạn lấy các tệp không có tiện ích mở rộng. Một hàm được xây dựng cụ thể cho mục đích đó sẽ chỉ đánh giá thời tiết nếu đối tượng được tìm thấy là một tệp và sau đó có hay không nếu tên của tệp có dấu chấm trong đó.
Việc tiết kiệm có thể không nhiều nếu bạn chỉ đọc các thư mục không có quá nhiều tệp. Nhưng nếu bạn đang đọc một lượng lớn thư mục hoặc nếu thư mục có vài trăm nghìn tệp, thì đó có thể là một khoản tiết kiệm rất lớn.
#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;
}
#include<iostream>
#include <dirent.h>
using namespace std;
char ROOT[]={'.'};
void listfiles(char* path){
DIR * dirp = opendir(path);
dirent * dp;
while ( (dp = readdir(dirp)) !=NULL ) {
cout << dp->d_name << " size " << dp->d_reclen<<std::endl;
}
(void)closedir(dirp);
}
int main(int argc, char **argv)
{
char* path;
if (argc>1) path=argv[1]; else path=ROOT;
cout<<"list files in ["<<path<<"]"<<std::endl;
listfiles(path);
return 0;
}
Điều này làm việc cho tôi. Nó viết một tệp chỉ có tên (không có đường dẫn) của tất cả các tệp. Sau đó, nó đọc tệp txt đó và in nó cho bạn.
void DisplayFolderContent()
{
system("dir /n /b * > file_names.txt");
char ch;
std::fstream myStream("file_names.txt", std::fstream::in);
while (myStream.get(ch))
{
std::cout << ch;
}
}