![](/img/trans.png)
[英]List files in a directory, not recursive, only files and no subdirectories, using C++
[英]Recursive listing files in C++ doesn't enter all subdirectories
謝謝你們的幫助,現在一切正常。 我按照@RSahu的建議對我的代碼進行了更改並使其正常工作。
感謝您的所有投入,我一直堅持這一點。
致@Basile:我肯定會檢查出來但是對於這段特殊的代碼,我不會用它,因為它看起來太復雜了:)但感謝您的建議。
我正在嘗試制作一個C ++代碼來列出給定目錄中的所有文件及其子目錄。
想法是函數list_dirs(_dir, _files, _current_dir)
將從頂級目錄開始並將文件放入vector _files
,當它找到目錄時,它將在此目錄上調用自己。 如果在子目錄中, _current_dir
將被添加到文件名之前,因為我需要知道路徑結構(它應該生成sitemap.xml)。
在list_dirs
有一個對list_dir
的調用, list_dir
返回當前目錄中的所有文件,而不是文件和目錄之間的區別。
現在的代碼是,它列出原始目錄中的所有文件,然后列出一個子目錄中的所有文件,但跳過所有其他子目錄。 它會列出它們,但不會列出它們中的文件。
而且更加神秘,它只列出這個特定目錄中的文件而不是其他目錄。 我嘗試在多個位置運行它,但它從未進入任何其他目錄。
在此先感謝,請注意我是C ++初學者,所以不要苛刻;)
LIST_DIR
int list_dir(const std::string& dir, std::vector<std::string>& files){
DIR *dp;
struct dirent *dirp;
unsigned fileCount = 0;
if ((dp = opendir(dir.c_str())) == NULL){
std::cout << "Error opening dir." << std::endl;
}
while ((dirp = readdir(dp)) != NULL){
files.push_back(std::string (dirp->d_name));
fileCount++;
}
closedir(dp);
return fileCount;
}
和LIST_DIRS
int list_dirs (const std::string& _dir, std::vector<std::string>& _files, std::string _current_dir){
std::vector<std::string> __files_or_dirs;
list_dir(_dir, __files_or_dirs);
std::vector<std::string>::iterator it = __files_or_dirs.begin();
struct stat sb;
while (it != __files_or_dirs.end()){
if (lstat((&*it)->c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)){
/* how to do this better? */
if (*it == "." || *it == ".."){
__files_or_dirs.erase(it);
continue;
}
/* here it should go into sub-directory */
list_dirs(_dir + *it, _files, _current_dir + *it);
__files_or_dirs.erase(it);
} else {
if (_current_dir.empty()){
_files.push_back(*it);
} else {
_files.push_back(_current_dir + "/" + *it);
}
++it;
}
}
}
主要問題在於:
if (lstat((&*it)->c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)){
您正在使用lstat
調用中的目錄條目的名稱。 當函數處理子目錄時,條目名稱不表示有效路徑。 你需要使用類似的東西:
std::string entry = *it;
std::string full_path = _dir + "/" + entry;
if (lstat(full_path.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)){
建議改進
更新list_dir
,使其不包含"."
或輸出中的".."
。 我開始排除這些文件是有道理的。
int list_dir(const std::string& dir, std::vector<std::string>& files){
DIR *dp;
struct dirent *dirp;
unsigned fileCount = 0;
if ((dp = opendir(dir.c_str())) == NULL){
std::cout << "Error opening dir." << std::endl;
}
while ((dirp = readdir(dp)) != NULL){
std::string entry = dirp->d_name;
if ( entry == "." or entry == ".." )
{
continue;
}
files.push_back(entry);
fileCount++;
}
closedir(dp);
return fileCount;
}
在list_dirs
,不需要從_files_or_dirs
刪除項目。 可以使用for
循環簡化代碼for
並刪除從_files_or_dirs
刪除項目的調用。
我不清楚_current_dir
的目的是什么。 也許它可以刪除。
這是該功能的更新版本。 _current_dir
僅用於在遞歸調用中構造參數的值。
int list_dirs (const std::string& _dir,
std::vector<std::string>& _files, std::string _current_dir){
std::vector<std::string> __files_or_dirs;
list_dir(_dir, __files_or_dirs);
std::vector<std::string>::iterator it = __files_or_dirs.begin();
struct stat sb;
for (; it != __files_or_dirs.end() ; ++it){
std::string entry = *it;
std::string full_path = _dir + "/" + entry;
if (lstat(full_path.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)){
/* how to do this better? */
/* here it should go into sub-directory */
list_dirs(full_path, _files, _current_dir + "/" + entry);
} else {
_files.push_back(full_path);
}
}
}
我不確定你的代碼中的所有問題,但我可以告訴你,這一行和另一個類似於它會導致你的問題:
__files_or_dirs.erase(it);
當你調用erase
你會在擦除點或之后使迭代器和引用無效,包括end()迭代器(參見這個擦除引用 )。 你正在調用erase然后不存儲返回的迭代器,然后在這次調用之后再次查看它,這不是一件好事。 您至少應該將行更改為此,以便捕獲返回的迭代器,該迭代器應指向擦除元素之后的元素(如果它是最后一個元素,則指向end()
)
it = __files_or_dirs.erase(it);
從您發布的代碼中也可以看出, _dir
和_current_dir
之間_dir
冗余。您不要修改它們中的任何一個。 您將它們作為相同的值傳遞,並且它們在整個函數執行期間保持相同的值。 除非這是簡化的代碼並且您正在做其他事情,否則我建議您刪除 _current_dir
並只使用_dir
。您可以使用 _dir
替換while循環中的_dir
,您將構建文件名,並且您將簡化代碼,這始終是一件好事。
對於這一行:
if (lstat((&*it)->c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)){
請注意, readdir
和因此list_dir
僅返回文件名 ,而不是完整文件路徑。 所以此時(&*it)->c_str()
只有一個文件名(例如“input.txt”),而不是完整路徑,所以當你在子目錄中的文件上調用lstat
時,系統不能找到它。
要解決此問題,您需要在調用lstat之前添加文件路徑。 就像是:
string fullFileName;
if (dir.empty()){
fullFileName = *it;
} else {
fullFileName = dir + "/" + *it;
}
if (lstat(fullFileName.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)){
您可能必須使用_currentDir
而不是dir
,具體取決於它們的實際用途(我無法按照您的解釋)。
Linux上更簡單的方法是使用nftw(3)函數。 它以遞歸方式掃描文件樹,並為其提供一些處理函數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.