红联Linux门户
Linux帮助

Linux下利用scandir判断是目录还是文件详解

发布时间:2016-09-13 11:05:19来源:blog.csdn.net/qq_21792169作者:Linux_Google
函数scandir的用法参考:Linux c目录操作函数scandir
头文件:#include  <dirent.h>
定义函数:int  scandir(const char *dir, struct dirent **namelist, nt (*select)  (const  struct  dirent *), nt (*compar)  (const struct dirent **, const struct dirent**));
函数说明:scandir()会扫描参数dir指定的目录文件,经由参数select指定的函数来挑选目录结构至参数namelist数组中,最后再调用参数compar指定的函数来排序namelist数组中的目录数据。每次从目录文件中读取一个目录结构后便将此结构传给参数select所指的函数, select函数若不想要将此目录结构复制到namelist数组就返回0,若select为空指针则代表选择所有的目录结构。scandir()会调用qsort()来排序数据,参数compar则为qsort()的参数,若是要排列目录名称字母则可使用alphasort(). 结构dirent定义请参考readdir()
返回值:成功则返回复制到namelist数组中的数据结构数目,有错误发生则返回-1
 
struct linux_dirent64 {  
u64 d_ino;    /* inode number 索引节点号 */  
s64 d_off;    /* offset to this dirent 在目录文件中的偏移 */  
unsigned short  d_reclen;   /* length of this d_name 文件名长 */  
unsigned char   d_type; /* the type of d_name 文件类型 */  
chard_name[0];  /* file name (null-terminated) 文件名,最长255字符 */  
};  
 
测试代码如下:
example  1
#include <stdio.h>  
#include <stdlib.h>  
#include <dirent.h>   
int main(void)  
{  
struct dirent **entry_list;  
int count;  
int i;  
count = scandir("/home/book/workspace", &entry_list, 0, alphasort);  
if (count < 0) {  
perror("scandir");  
return EXIT_FAILURE;  
}  
for (i = 0; i < count; i++) {  
struct dirent *entry;  
entry = entry_list[i];  
printf("%s\n", entry->d_name);  
free(entry);  
}  
free(entry_list);   
return 0;  
}
 
example  2
#define _GNU_SOURCE   
#include <stdio.h>  
#include <stdlib.h>  
#include <sys/stat.h>  
#include <fcntl.h>  
#include <dirent.h>  
void make_test_data(char *path)  
{  
int i;  
for (i = 0; i < 20; i++) {  
char file[128];  
sprintf(file, "file-%d", i);  
creat(file, 0);  
}  
}   
void scan(char *path, char *title, int (*sort)(const void *a, const void *b))  
{  
struct dirent **entry_list;  
int count;  
int i;  
puts(title);  
count = scandir(path, &entry_list, 0, sort);  
if (count < 0) {  
perror("scandir");  
return EXIT_FAILURE;  
}  
for (i = 0; i < count; i++) {  
struct dirent *entry;  
entry = entry_list[i];  
printf("%s\n", entry->d_name);  
free(entry);  
}  
printf("\n");  
free(entry_list);  
}  
int main(void)  
{  
char *path = ".";  
make_test_data(path);  
scan(path, "alphasort: ", alphasort);  
scan(path, "versionsort: ", versionsort);  
return 0;  
}  
 
example  3
#include <stdio.h>  
#include <stdlib.h>  
#include <dirent.h>  
int filter(const struct dirent *entry)  
{  
return entry->d_name[0] == 'a';  
}  
int main(void)  
{  
struct dirent **entry_list;  
int count;  
int i;  
count = scandir("/usr/include", &entry_list, filter, alphasort);  
if (count < 0) {  
perror("scandir");  
return EXIT_FAILURE;  
}  
for (i = 0; i < count; i++) {  
struct dirent *entry;  
entry = entry_list[i];  
printf("%s\n", entry->d_name);  
free(entry);  
}  
free(entry_list);  
return 0;  
}
 
对文件操作我们经常和这个stat结构体打交道:linux-3.4.2\include\asm-generic\Stat.h
Linux下利用scandir判断是目录还是文件详解
这个结构体就把文件的所有信息都包含在其中了,其中很重要的一个成员是:unsigned intst_mode;/* File mode.  */
这个成员选项定义 \linux-3.4.2\include\linux\Stat.h中:
Linux下利用scandir判断是目录还是文件详解
S_ISLNK(st_mode):是否是一个连接.
S_ISREG是否是一个常规文件.
S_ISDIR是否是一个目录
S_ISCHR是否是一个字符设备
S_ISBLK是否是一个块设备
S_ISFIFO是否 是一个FIFO文件
S_ISSOCK是否是一个SOCKET文件
 
例子一:
下面我们开发一个小程序,这个程序有一个参数.如果这个参数是一个文件名,我们输出这个文件的大小和最后修改的时间,如果是一个目录我们输出这个目录下所有文件的大小和修改时间.
代码如下:
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <time.h>
static int get_file_size_time(const char *filename) {
struct stat statbuf;
if (stat(filename, &statbuf) == -1) {
printf("Get stat on %s Error:%s\n",
filename, strerror(errno));
return (-1);
}
if (S_ISDIR(statbuf.st_mode))return (1);
if (S_ISREG(statbuf.st_mode))
printf("%s size:%ld bytes\tmodified at %s",
filename, statbuf.st_size, ctime(&statbuf.st_mtime));
return (0);
}
int main(int argc, char **argv) {
DIR *dirp;
struct dirent *direntp;
int stats;
char buf[80];
if (argc != 2) {
printf("Usage:%s filename\n\a", argv[0]);
exit(1);
}
if (((stats = get_file_size_time(argv[1])) == 0) || (stats == -1))exit(1);
if ((dirp = opendir(argv[1])) == NULL) {
printf("Open Directory %s Error:%s\n",
argv[1], strerror(errno));
exit(1);
}
while ((direntp = readdir(dirp)) != NULL){
sprintf(buf,"%s/%s",argv[1],direntp->d_name);
if (get_file_size_time(buf) == -1)break;
}
closedir(dirp);
exit(1);
}
 
例子二:
测试检测出来的文件,分辨它是目录还是普通文件
#include <dirent.h>
#include <sys/types.h>  
#include <sys/stat.h>  
#include <unistd.h>    
#include <stdlib.h>  
#include <stdio.h>  
int main()  
{  
struct dirent **namelist;  
struct stat tStat;  
int n;  
char strTmp[256];  
n = scandir("../", &namelist, NULL, alphasort);  
if (n < 0)  
perror("scandir");  
else {  
while (n--) {
snprintf(strTmp, 256, "%s/%s", "../", namelist[n]->d_name);  
strTmp[255] = '\0';  
if ((stat(strTmp, &tStat) == 0))  
{  
if(S_ISDIR(tStat.st_mode))  
{  
printf("%s:is a dir\n", namelist[n]->d_name);  
}  
else if(S_ISREG(tStat.st_mode))  
{  
printf("%s:is a file\n", namelist[n]->d_name);  
}  
else  
{  
printf("%s:unknow2\n", namelist[n]->d_name);  
}
}  
free(namelist[n]);  
}  
free(namelist);  
}  
return 0;  
}
 
本文永久更新地址:http://www.linuxdiyf.com/linux/24122.html