目录操作有关的函数在dirent.h中声明。
它们使用一个名为DIR的的结构作为目录操作的基础。使用目录流的指针(DIR *)完成各种目录操作,使用和FILE *类似。
目录数据项本身在dirent结构中返回,dirent结构也声明在dirent.h中。
使用到的函数:
- opendir、closedir
- readdir
- closedir
opendir函数
man opendir,查看具体信息。
函数原型:
/*
函数功能:打开一个目录并建立一个目录流。
参数:name--目录位置
返回值:成功--返回一个指向DIR结构的指针,该指针用于读取目录数据项。
失败--返回一个空指针。
*/
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
readdir函数
函数原型:
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
closedir函数
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
一个目录扫描程序(ls)
struct _dirstream {
void *_fd;
char *_data;
int _entry_data;
char *_ptr;
int _entry_ptr;
size_t _allocation;
size_t __size;
__libc_lock_define(, __lock);
};
typedef struct _dirstream DIR;
struct dirent
{
long d_ino; /* inode number 索引节点号 /
off_t d_off; / offset to this dirent 在目录文件中的偏移 /
unsigned short d_reclen; / length of this d_name 文件名长 /
unsigned char d_type; / the type of d_name 文件类型 /
char d_name [NAME_MAX+1]; / file name (null-terminated) 文件名,最长256字符 */
}
要想输出类似于ls -l那么详细的信息,只依靠struct dirent是不够的:
strcut stat {
mode_t st_mode; //文件访问权限
ino_t st_ino; //索引节点号
dev_t st_dev; //文件使用的设备号
dev_t st_rdev; //设备文件的设备号
nlink_t st_nlink; //文件的硬连接数
uid_t st_uid; //所有者用户识别号
gid_t st_gid; //组识别号
off_t st_size; //以字节为单位的文件容量
time_t st_atime; //最后一次访问文件的时间
time_t st_mtime; //最后一次修改该文件的时间
time_t st_ctime; //最后一次改变该文件状态的时间
blksize_t st_blksize; //包含该文件的磁盘块的大小
blkcnt_t st_blocks; //该文件所占用的磁盘块
}
struct passwd {
char *pw_name; /*user name */
char *pw_passwd; /*user password */
uid_t pw_uid; /*user id */
gid_t pw_gid; /*group id */
char *pw_gecos; /*user real name */
char *pw_dir; /*home directory */
char *pw_shell; /*shell program */
};
struct group
{
char gr_name; / Group name. */
char gr_passwd; / Password. /
__gid_t gr_gid; / Group ID. */
char *gr_mem; / Member list. */
};
一个简单的ls程序:
/*
myls实现的简单功能:
myls 默认输出当前目录下的文件
myls -d dir 输出dir目录下的文件
myls -a -d dir 输出dir目录下所有文件
myls -l -d dir 输出dir目录下文件的详细信息
*/
#include <apue.h> /*《UNIX环境高级编程》作者对常用函数等的封装*/
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <unistd.h>
void printDir(const char* d_name);
void mode2string(int st_mode, char *str);
char *uid2name(uid_t uid);
char *gid2name(gid_t did);
char *time2string(time_t time);
int printall, printdetail; /*打印标志*/
int main(int argc, char *argv[])
{
/*只支持单划线的参数*/
DIR *dp;
struct dirent *dirp;
char *curDir = "."; /*默认目录为当前目录*/
int opt;
while((opt = getopt(argc, argv, "ald:")) != -1){
switch(opt){
case 'a':
printall = 1;
break;
case 'l':
printdetail = 1;
break;
case 'd':
curDir = optarg;
break;
case '?':
return -1;
default:
printf("usage:./myls -al .");
break;
}
}
/*打开目录*/
if((dp = opendir(curDir)) == NULL)
err_sys("can't open %s", argv[1]);
/*改变当前工作目录*/
chdir(curDir);
/*读取目录项*/
while((dirp = readdir(dp)) != NULL){
printDir(dirp->d_name);
}
/*关闭目录*/
closedir(dp);
return 0;
}
void printDir(const char* d_name)
{
struct stat statBuf;
char mode[11];
char uidName[10];
char gidName[10];
char lastChgStatTime[30];
memset(mode, 0, 11);
memset(uidName, 0, 10);
memset(gidName, 0, 10);
memset(lastChgStatTime, 0, 30);
if(printall != 1){
/*忽略.和..目录*/
if((strcmp(d_name, ".") == 0) || (strcmp(d_name, "..") == 0)){
return;
}
/*忽略隐藏文件*/
if(d_name[0] == '.'){
return;
}
}
/************************/
/*根据文件名获取文件属性*/
/************************/
if(0 == lstat(d_name, &statBuf)){
if(printdetail != 1){
printf("%-s\n", d_name); /*文件名*/
}else{
/*获取rwxrwxrwx形式的访问权限表示*/
mode2string(statBuf.st_mode, mode);
/*获取uid,gid对应的名称*/
strncpy(uidName, uid2name(statBuf.st_uid), strlen(uid2name(statBuf.st_uid)));
strncpy(gidName, gid2name(statBuf.st_gid), strlen(gid2name(statBuf.st_gid)));
/*time_t转为可读字符串*/
strncpy(lastChgStatTime, time2string(statBuf.st_ctime), strlen(time2string(statBuf.st_ctime)));
/*文件信息打印,没有把struct stat中的信息全部打印*/
printf("%-10s ", mode); /*文件访问权限*/
printf("%3d ", statBuf.st_nlink); /*文件的硬连接数*/
printf("%s ", uidName); /*所有者用户识别号*/
printf("%s ", gidName); /*组识别号*/
printf("%10dB ", statBuf.st_size); /*以字节为单位的文件容量*/
printf("%s ", lastChgStatTime); /*最后一次改变该文件状态的时间*/
printf("%-s\n", d_name); /*文件名*/
}
}else{
err_sys("cant't get attribute");
}
}
void mode2string(int st_mode, char str[])
{
strncpy(str, "----------", 10);
/*文件类型判断*/
if(S_ISREG(st_mode)){ /*普通文件*/
str[0] = '-';
}else if(S_ISDIR(st_mode)){ /*目录*/
str[0] = 'd';
}else if(S_ISLNK(st_mode)){ /*链接文件*/
str[0] = 'l';
}
/*用户权限位*/
if(st_mode & S_IRUSR)
str[1] = 'r';
if(st_mode & S_IWUSR)
str[2] = 'w';
if(st_mode & S_IXUSR)
str[3] = 'x';
/*组权限位*/
if(st_mode & S_IRGRP)
str[4] = 'r';
if(st_mode & S_IWGRP)
str[5] = 'w';
if(st_mode & S_IXGRP)
str[6] = 'x';
/*其它组权限位*/
if(st_mode & S_IROTH)
str[7] = 'r';
if(st_mode & S_IWOTH)
str[8] = 'w';
if(st_mode & S_IXOTH)
str[9] = 'x';
}
char *uid2name(uid_t uid)
{
return getpwuid(uid)->pw_name;
}
char *gid2name(gid_t gid)
{
return getgrgid(gid)->gr_name;
}
char *time2string(time_t time)
{
char *timeString = ctime(&time);
/*默认的时间字符串会自己换行*/
timeString[strlen(timeString) - 1] = '\0';
return timeString;
}
文件没有排序,输出字段间隔也没调好。。。支持选项不多。。。
[root@20:26:25 1-4]$./myls -l -a -d /root
-rw-r--r-- 1 root root 427480B Fri Jun 26 13:50:09 2020 unpv13e.tar.gz
-rw-r--r-- 1 root root 147B Thu Mar 12 14:40:02 2020 variable.cpp
-rw-r--r-- 1 root root 18B Fri Aug 18 11:52:03 2017 .bash_logout
drwxr-xr-x 2 root root 4096B Fri Aug 18 12:00:32 2017 .pip
-rw------- 1 root root 102B Mon May 25 13:06:44 2020 .rediscli_history
-rw-r--r-- 1 root root 4678B Sat Jul 11 18:01:29 2020 netopeer-manager.txt
drwxr-xr-x 7 root root 4096B Sun Jul 5 12:33:56 2020 netconf
drwx------ 2 root root 4096B Sun Jul 5 12:58:38 2020 .ssh
-rw-r--r-- 1 root root 0B Thu Mar 12 14:42:53 2020 Sales_item.cpp
-rw-r--r-- 1 root root 1512B Wed Jun 3 21:05:59 2020 passwd
-rw-r--r-- 1 root root 92830B Sun Mar 29 10:14:13 2020 src.3e.tar.gz
-rw-r--r-- 1 root root 100B Fri Aug 18 11:52:03 2017 .cshrc