下面的代码是列出指定目录下的所有文件和目录,且支持递归搜索算法。
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdbool.h>
/**
* List all the files and directories under the specified directory, recursively.
*
*/
void list_files(const char* directory, char*** filenames, int* file_count, int* array_size)
{
DIR* dir;
struct dirent* de;
char file_name[FILENAME_MAX];
struct stat st;
dir = opendir(directory);
if (NULL == dir) {
printf("ERROR: open failed: %s(%s)\n", directory, strerror(errno));
return;
}
bool end_with_slash = ('/' == directory[strlen(directory) - 1]);
bool is_dir;
while ((de = readdir(dir)) != 0) {
strcpy(file_name, directory);
if (!end_with_slash) strcat(file_name, "/");
strcat(file_name, de->d_name);
printf("de->d_name: %s\n", de->d_name);
if ('.' == de->d_name[0]) {
if (0 == de->d_name[1]) continue; // .
if (('.' == de->d_name[1]) && (0 == de->d_name[2])) continue; // ..
}
if (stat(file_name, &st) != 0) {
printf("stat failed: %s, %s\n", file_name, strerror(errno));
continue;
}
if ((is_dir = S_ISDIR(st.st_mode)) || S_ISREG(st.st_mode)) {
if (*file_count > *array_size) {
*array_size = (*array_size) * 2;
*filenames = (char**)realloc(*filenames, (*array_size) * sizeof(char*));
}
(*filenames)[(*file_count)++] = strdup(file_name);
if (is_dir) {
list_files(file_name, filenames, file_count, array_size);
}
} else {
printf("Other files: %s\n", file_name);
}
}
closedir(dir);
}
static void test(const char* directory)
{
char** filenames;
int file_count = 0;
int array_size = 16;
filenames = (char**)malloc(array_size * sizeof(char*));
if (NULL == filenames) {
printf("No memory.\n");
return;
}
list_files(directory, &filenames, &file_count, &array_size);
printf("All files:\n");
for (int i = 0; i < file_count; i++) {
printf("%s\n", filenames[i]);
free(filenames[i]);
filenames[i] = NULL;
}
free(filenames);
}
int main(int argc, const char* argv[])
{
if (argc != 2) {
printf("Usage: %s dir_name\n", argv[0]);
return 1;
}
test(argv[1]);
return 0;
}
目录结构 示例:
flying-bird@flyingbird:~/examples/cpp/list_files/test$ ll . a/ b/
.:
total 24
drwxrwxr-x 4 flying-bird flying-bird 4096 7月 27 20:31 ./
drwxrwxr-x 3 flying-bird flying-bird 4096 7月 27 20:31 ../
drwxrwxr-x 2 flying-bird flying-bird 4096 7月 27 20:31 a/
drwxrwxr-x 2 flying-bird flying-bird 4096 7月 27 20:31 b/
-rw-rw-r-- 1 flying-bird flying-bird 6 7月 27 20:31 first.txt
-rw-rw-r-- 1 flying-bird flying-bird 7 7月 27 20:31 second.txt
a/:
total 16
drwxrwxr-x 2 flying-bird flying-bird 4096 7月 27 20:31 ./
drwxrwxr-x 4 flying-bird flying-bird 4096 7月 27 20:31 ../
-rw-rw-r-- 1 flying-bird flying-bird 6 7月 27 20:31 first.txt
-rw-rw-r-- 1 flying-bird flying-bird 7 7月 27 20:31 second.txt
b/:
total 16
drwxrwxr-x 2 flying-bird flying-bird 4096 7月 27 20:31 ./
drwxrwxr-x 4 flying-bird flying-bird 4096 7月 27 20:31 ../
-rw-rw-r-- 1 flying-bird flying-bird 6 7月 27 20:31 first.txt
-rw-rw-r-- 1 flying-bird flying-bird 7 7月 27 20:31 second.txt
flying-bird@flyingbird:~/examples/cpp/list_files/test$
再增加一个symlink:
flying-bird@flyingbird:~/examples/cpp/list_files/test$ ln -s test test
flying-bird@flyingbird:~/examples/cpp/list_files/test$ ll
total 24
drwxrwxr-x 4 flying-bird flying-bird 4096 7月 27 20:43 ./
drwxrwxr-x 3 flying-bird flying-bird 4096 7月 27 20:38 ../
drwxrwxr-x 2 flying-bird flying-bird 4096 7月 27 20:31 a/
drwxrwxr-x 2 flying-bird flying-bird 4096 7月 27 20:31 b/
-rw-rw-r-- 1 flying-bird flying-bird 6 7月 27 20:31 first.txt
-rw-rw-r-- 1 flying-bird flying-bird 7 7月 27 20:31 second.txt
lrwxrwxrwx 1 flying-bird flying-bird 4 7月 27 20:43 test -> test
flying-bird@flyingbird:~/examples/cpp/list_files/test$
没有symlink时的运行示例:
flying-bird@flyingbird:~/examples/cpp/list_files$ ./a.out ./test/
de->d_name: b
de->d_name: first.txt
de->d_name: second.txt
de->d_name: .
de->d_name: ..
de->d_name: first.txt
de->d_name: second.txt
de->d_name: .
de->d_name: ..
de->d_name: a
de->d_name: first.txt
de->d_name: second.txt
de->d_name: .
de->d_name: ..
All files:
./test/b
./test/b/first.txt
./test/b/second.txt
./test/first.txt
./test/second.txt
./test/a
./test/a/first.txt
./test/a/second.txt
flying-bird@flyingbird:~/examples/cpp/list_files$
增加symlink的运行示例:
flying-bird@flyingbird:~/examples/cpp/list_files$ ./a.out test/
de->d_name: b
de->d_name: first.txt
de->d_name: second.txt
de->d_name: .
de->d_name: ..
de->d_name: first.txt
de->d_name: second.txt
de->d_name: .
de->d_name: test
stat failed: test/test, Too many levels of symbolic links
de->d_name: ..
de->d_name: a
de->d_name: first.txt
de->d_name: second.txt
de->d_name: .
de->d_name: ..
All files:
test/b
test/b/first.txt
test/b/second.txt
test/first.txt
test/second.txt
test/a
test/a/first.txt
test/a/second.txt
flying-bird@flyingbird:~/examples/cpp/list_files$