searching a directory for folders - c++

I'm trying to write a program that gets the path of a folder and prints directories' names inside it.
This is my code:
if ((dir = opendir (file_path)) != NULL)
{
while ((ent = readdir (dir)) != NULL)
{
if (stat(ent->d_name, &dir_stat)== 0)
{
if( dir_stat.st_mode & S_IFDIR )
{
if(strncmp(ent->d_name, "." ,sizeof(ent->d_name)) != 0
&& strncmp(ent->d_name, "..",sizeof(ent->d_name)) != 0)
cout<<"dir : "<< ent->d_name<<endl;
}
}
}
}
Now the problem is that when I give it "." as file_path it works correctly but when I give it, ./folder as file_path, it does not print anything. Any ideas how to fix it? Thanks in advance.

The problem is that readdir() returns the name of the subdirectories, not the path to get to them.
For example if you have a ./folder/sub then when reading the ./folder you will get just sub as the name. Then, doing a stat("sub") will not work, you have to concatenate the directory you are reading:
while ((ent = readdir (dir)) != NULL)
{
std::string path = dir;
path += ent->d_name;
if (stat(path.c_str(), &dir_stat)== 0)
{
It is usually a good idea to add some perror() calls after your system calls:
if (stat(path.c_str(), &dir_stat) < 0)
perror(path.c_str());
else
{
...

Related

readdir excludes some files in a directory

I have a fairly simple piece of code to get a list of files in a directory in C++. Inexplicably, only 68 of 135 files in the directory end up being stored in the vector fileNames. What is happening?
DIR* pDIR = opendir(directoryName.c_str());
struct dirent* entry = nullptr;
vector<string> fileNames;
while(readdir(pDIR)) {
entry = readdir(pDIR);
if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0 )
fileNames.push_back(entry->d_name);
}
closedir(pDIR);
You are executing readdir 2 times for every iteration. So, you are skipping the half of files.
The fix is easy, just call one time:
DIR* pDIR = opendir(directoryName.c_str());
struct dirent* entry = nullptr;
vector<string> fileNames;
while(entry = readdir(pDIR)) {
if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0 )
fileNames.push_back(entry->d_name);
}
closedir(pDIR);

Recursive count_files function not returning complete results

I am writing a recursive function in C/C++ for counting all files and directories within a given file path and it's subdirectories. The function has two parameters- the search directory and the file_count int, set by default to a value of 0.
int count_files(char * directory, int file_count = 0) {
DIR * dirp;
struct dirent * entry;
dirp = opendir(directory);
while ((entry = readdir(dirp)) != NULL) {
if (entry->d_type == DT_REG) {
file_count++;
} else if(entry->d_type == DT_DIR) {
if(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
} else {
file_count++;
char rcsvdir[256];
sprintf(rcsvdir, "%s%s/", directory, entry->d_name);
count_files(rcsvdir, file_count);
}
}
}
closedir(dirp);
return file_count;
}
The trouble I'm having is that it doesn't count all files in subdirectories. Imagine a directory with subdirectories like this:
-root
file1
file2
file3
-sub1
file1
file2
-sub2
file1
file2
The expected return integer would be 9 (2 dirs, 7 files), though it returns 5. To my understanding, it is counting all files in the root directory, but only the first file in the subdirectories. Any help as to why this may be happening would be greatly appreciated.
Update
The issue was resolved by replacing this line:
count_files(rcsvdir, file_count);
with the following:
file_count = count_files(rcsvdir, file_count);
Thanks to #IInspectable
You ignore the return value of the recursive function, you likely need:
char rcsvdir[256];
sprintf(rcsvdir, "%s%s/", directory, entry->d_name);
file_count += count_files(rcsvdir, file_count);
Instead of:
file_count++;
....
count_files(rcsvdir, file_count);
This way instead of forgetting the amount of files returned by the function and only incrementing by 1, you are incrementing the number of files found in the subdirectory.

How to get real file name without tilde substitution

I use dirent.h library for fetching name of file. While most of them are correct, this one:
1Zdjęcie główne.JPG_38ba97e477158efb3563274f5bd39af7.jpg_cda6829b61253f64b44a5c7f15e00b45 - Copy.jpg
is read as
1ZDJCI~2.JPG
What can I do to prevent tilde substition behavior?
I use Windows 7, Visual Studio C++
path "./tiles/"
DIR *dir;
struct dirent *ent;
if ((dir = opendir(path.c_str())) != NULL) {
while ((ent = readdir(dir)) != NULL) {
if( strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0 ) { continue; }
string a(ent->d_name);
examples of "correct" (without tilde substitution) file names:
"2012-07-29-
227.jpg_955c70788013c4979d5cad857b49d4d2.jpg_8551b27380326b183c17e3469ec97cd3.jpg"
"2012-07-29-228.jpg_5b2281bbe1efd6bd7469c4a29114a210.jpg_ee6d3a75864e7e33b3d99c023c962dbf.jpg"
"2012-08-31-842.jpg_93562fa908083e5a070467558bba2141.jpg_2e84cdbc1d5a5eb932a1373840119aa4.jpg"
You can call GetLongPathName to convert the short name (NAME~1.EXT) to it's long name.

How can I find the file by its part of name

How can I find the a file by its part of name in c++/linux?
The file full name maybe like:
foo.db.1
or
foo.db.2
How can I find the file by part of its name "foo.db", Thanks
The Posix standard function for your use case is glob(). Earlier somebody posted an easy to use C++ wrapper around it here on Stackoverflow.
For example with:
find /your/path -name "foo.db.*"
It will match all files in /your/path structure whose name is like foo.db.<something>.
If the text after db. is always a number, you can do:
find /your/path -name "foo.db.[0-9]*"
You can also use ls:
ls -l /your/path/ls.db.[0-9]
to get files whose name is like foo.db.<number> or even
ls -l /your/path/ls.db.[0-9]*
to get files whose name is like foo.db.<different numbers>
Do like this:
find /filepath -name "foo.db*"
In C/C++, you can do like this:
void findFile(const char *path)
{
DIR *dir;
struct dirent *entry;
char fileName[] = "foo.db";
if (!(dir = opendir(path)))
return;
if (!(entry = readdir(dir)))
return;
do {
if (entry->d_type == DT_DIR) {
char path[1024];
int len = snprintf(path, sizeof(path)-1, "%s/%s", path, entry->d_name);
path[len] = 0;
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
if(strstr(fileName, entry->d_name) != NULL) {
printf("%s\n", "", entry->d_name);
}
findFile(path);
}
else
printf(" %s\n", "", entry->d_name);
} while (entry = readdir(dir));
closedir(dir);
}

check if node represents directory in c++

I have to list all directories in some folders in my application. To do so I've written something of this kind:
std::vector<std::string> FirefoxCleaner::_getDirs(std::string path) {
std::vector<std::string>* dirs = new std::vector<std::string>();
std::cout<<DT_DIR<<std::endl;
DIR *dir = opendir(path.c_str());
struct dirent *entry = readdir(dir);
while (entry != NULL) {
std::cout<<entry->d_name<<": "<<entry->d_type<<std::endl;
if (entry->d_type == DT_DIR) {
std::cout<<entry->d_name<<std::endl;
//dirs.push_back(entry->d_name);
}
entry = readdir(dir);
}
closedir(dir);
return *dirs;
}
I've commented push_back line because I don't need it for the moment (and I know it should be -> instead of . sign there). However though the result of this method is:
16
.: 24
..: 24
extensions: 24
lidv7pj1.default: 24
v0kmwatk.defaultextensions.ini: 24
As you can imagine extensions and lidv7pj1.default are in fact directories. How can I determine it?
The d_type entry is a bitmask, so you need to check it using &:
if (entry->d_type & DT_DIR)
should solve this.