Linux命令行下有两个非常基本的命令,一个是ls,一个是tree,其分别能够列出当前目录下的文件和树形方式嵌套显示目录结构。
因为网络上有很多版本的文件遍历代码,代码都没有整理过,看起来也很累,这里正好有点时间汇总整理下,并做一个练习。
同时,对一些POSIX淘汰接口进行一些解释,来帮助大家了解为什么有的代码会segfault。
通用版本的dir嵌套遍历
#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#define PATH_LEN 1024
int count = 0;
void dir_scan(char *path, char *file)
{
struct stat s;
DIR *dir;
struct dirent *dt;
char dirname[PATH_LEN];
memset(dirname, 0, PATH_LEN*sizeof(char));
strcpy(dirname, path);
if(stat(file, &s) < 0)
{
printf( "lstat error\n ");
}
if(S_ISDIR(s.st_mode))
{
strcpy(dirname+strlen(dirname), file);
strcpy(dirname+strlen(dirname), "/");
if((dir = opendir(file)) == NULL)
{
printf( "opendir %s/%s error\n ");
exit(4);
}
if(chdir(file) < 0)
{
printf( "chdir error\n ");
exit(5);
}
while((dt = readdir(dir)) != NULL)
{
if(dt-> d_name[0] == '.')
{
continue;
}
dir_scan(dirname, dt-> d_name);
}
if(chdir( "..") < 0)
{
printf( "chdir error\n ");
exit(6);
}
}else
{
printf( "%s%s\n ", dirname, file);
count++;
}
}
int main(int argc, char *argv[])
{
struct stat s;
if(argc != 2)
{
printf( "dir path needed.\n ");
exit(1);
}
if(lstat(argv[1], &s) < 0)
{
printf( "lstat error\n ");
exit(2);
}
if(!S_ISDIR(s.st_mode))
{
printf( "%s is not a dir name\n ", argv[1]);
exit(3);
}
dir_scan( "", argv[1]);
printf( "total: %d files\n ", count);
exit(0);
}
编译并执行命令
$ gcc dir.c -o dir
$ ./dir version/
version//version.tar.gz
version//version.h
version//main.c
version//version.c
version//Makefile
total: 5 files
文件时间信息dir嵌套遍历
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#define PATH_LEN 1024
int global_count = 0;
void do_search_dir(char *path)
{
DIR *dir;
char fullpath[PATH_LEN],currfile[PATH_LEN];
struct dirent *s_dir;
struct stat file_stat;
int local_count = 0;
strcpy(fullpath,path);
dir=opendir(fullpath);
while((s_dir=readdir(dir)) != NULL)
{
if((strcmp(s_dir-> d_name, ".")==0)||(strcmp(s_dir-> d_name, "..")==0))
{
continue;
}
sprintf(currfile, "%s/%s",fullpath,s_dir-> d_name);
stat(currfile,&file_stat);
if(S_ISDIR(file_stat.st_mode))
{
printf("\n------[Directory] %s is Directory,Judged by S_ISDIR\n", s_dir-> d_name);
do_search_dir(currfile);
} else
{
printf("\n[File] %s; path: %s\n",s_dir-> d_name, currfile);
printf("Owner ID: %d,Group ID: %d\n",file_stat.st_uid,file_stat.st_gid);
printf("Last Access Time: %s",ctime(&file_stat.st_atime));
printf("Last Modification Time: %s",ctime(&file_stat.st_mtime));
printf("Last Status Change Time: %s",ctime(&file_stat.st_ctime));
global_count++;
local_count++;
}
}
printf( "^^^^^^[Directory] %s local count: %d files\n", path, local_count);
closedir(dir);
}
int main(int argc, char **argv)
{
struct stat s;
if(argc != 2)
{
printf( "dir path needed.\n ");
exit(1);
}
if(lstat(argv[1], &s) < 0)
{
printf( "lstat error\n ");
exit(2);
}
if(!S_ISDIR(s.st_mode))
{
printf( "%s is not a dir name\n ", argv[1]);
exit(3);
}
printf("\n++++++[Directory] %s is Directory\n", argv[1]);
do_search_dir(argv[1]);
printf("++++++global count: %d files\n ", global_count);
exit(0);
}
编译并执行
$ gcc dir2.c -o dir2 -m32
$ ./dir2 version/
++++++[Directory] version/ is Directory
[File] version.tar.gz; path: version//version.tar.gz
Owner ID: 1000,Group ID: 1000
Last Access Time: Tue May 10 18:57:43 2016
Last Modification Time: Tue May 10 18:57:43 2016
Last Status Change Time: Tue May 10 18:57:43 2016
[File] version.h; path: version//version.h
Owner ID: 1000,Group ID: 1000
Last Access Time: Tue May 10 18:44:08 2016
Last Modification Time: Tue May 10 18:41:24 2016
Last Status Change Time: Tue May 10 18:42:08 2016
[File] main.c; path: version//main.c
Owner ID: 1000,Group ID: 1000
Last Access Time: Tue May 10 18:44:08 2016
Last Modification Time: Tue May 10 18:43:12 2016
Last Status Change Time: Tue May 10 18:43:12 2016
[File] version.c; path: version//version.c
Owner ID: 1000,Group ID: 1000
Last Access Time: Tue May 10 18:44:08 2016
Last Modification Time: Tue May 10 18:41:24 2016
Last Status Change Time: Tue May 10 18:42:08 2016
[File] Makefile; path: version//Makefile
Owner ID: 1000,Group ID: 1000
Last Access Time: Tue May 10 18:44:08 2016
Last Modification Time: Tue May 10 18:44:05 2016
Last Status Change Time: Tue May 10 18:44:05 2016
^^^^^^[Directory] version/ local count: 5 files
++++++global count: 5 files
POSIX淘汰接口
因为asctime, ctime, gmtime, localtime, mktime, asctime_r, ctime_r, gmtime_r, localtime_r都是日期时间转换API函数,其中POSIX.1-2008废弃了asctime(), asctime_r(), ctime(), and ctime_r(),所以64位系统上,这些函数将会产生segfault,需要采用gcc -m32来编译链接32位的库。
注:详细信息可以采用man ctime来查询。
POSIX.1-2001. C89 and C99 specify asctime(), ctime(), gmtime(), localtime(), and mktime(). POSIX.1-2008 marks asctime(), asctime_r(), ctime(), and ctime_r() as obsolete, recommending the use of strftime(3) instead.
所以dir2.c需要采用gcc的-m32来编译,否则将会出现如下问题:
$ gcc dir2.c -o dir2
$ ./dir2 version/
++++++[Directory] version/ is Directory
[File] version.tar.gz; path: version//version.tar.gz
Owner ID: 1000,Group ID: 1000
Segmentation fault