持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情
Linux下opendir()、readdir()和closedir()这三个函数主要用来遍历目录。并介绍目录创建、权限设置,目录删除、目录路径获取、路径剔除处理等函数用法。
1.1 打开目录
头文件
| #include <sys/types.h>#include <dirent.h> |
函数原型
| DIR *opendir(const char *name); |
参数
const char *name :目录的地址。
返回值
成功返回一个指针指向的目录流。
执行错误,返回NULL。
1.2 关闭目录
头文件
| #include <sys/types.h>#include <dirent.h> |
函数原型
| int closedir(DIR *dirp); |
功能
关闭指定的目录。
返回值
0表示成功,-1表示失败。
1.3 读取目录
头文件
| #include <sys/types.h>#include <dirent.h> |
函数原型
| struct dirent *readdir(DIR *dirp);int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result); //readdir的可重入版本 |
readdir函数返回值:失败返回空NULL。
readdir_r函数返回值:成功时返回0。错误时,它返回一个正的错误码。如果到达目录结尾,readdir_r() 返回0,并且把 *result 设置为 NULL。
相关结构体:
| struct dirent |
| {ino_t d_ino; /* 节点号 */ |
| off_t d_off; /* 偏移量 */ |
| unsigned short d_reclen; /* 文件的长度*/ |
| unsigned char d_type; /* 文件的类型*/ |
| char d_name[256]; /* 文件名称 */}; |
遍历目录示例:
| #include <sys/types.h> |
| #include <dirent.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| int main(int argc,char **argv) |
| { |
| if(argc!=2) |
| { |
| printf("error! usg: ./app dir"); |
| exit(-1); |
| } |
| DIR *dirp=NULL; |
| dirp=opendir(argv[1]); |
| if(dirp==NULL){printf("error!!\n"); |
| exit(-1);} |
| struct dirent *dir;//循环遍历目录 |
| while(dir=readdir(dirp)) |
| { |
| printf("%s\n",dir->d_name); //打印文件的名称 |
| } |
| closedir(dirp); |
| //关闭目录return 0; |
| } |
1.4 设置读取的偏移量位置
头文件
| #include <sys/types.h>#include <dirent.h> |
函数原型
| void seekdir(DIR *dirp, long offset); |
设置readfir函数的读取指针位置。
1.5 返回当前目录位置相对目录头的偏移量
函数原型
| #include <dirent.h>long telldir(DIR *dirp); |
获取当前目录指针的位置。相对目录头的偏移量。
打印出文件目录的偏移位置:
| #include <sys/types.h> |
| #include <dirent.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| int main(int argc,char **argv) |
| {if(argc!=2) |
| {printf("error! usg: ./app dir");exit(-1);} |
| DIR *dirp=NULL;dirp=opendir(argv[1]); |
| if(dirp==NULL){printf("error!!\n");exit(-1);} |
| struct dirent *dir;long len;//循环遍历目录 |
| while(dir=readdir(dirp)){len=telldir(dirp);printf("%s ",dir->d_name); //打印文件的名称 |
| printf("%d\n",len);}return 0;} |
1.6 目录操作函数总汇
1.6.1 获取目录信息相关的函数
需要包含的头文件:
| #include <sys/types.h>#include <dirent.h> |
相关的函数API:
| DIR *opendir(const char *name); //打开一个目录 |
| struct dirent *readdir(DIR *dir); //读取目录的一项信息,并返回该项信息的结构体指针 |
| void rewinddir(DIR *dir); //重新定位到目录文件的头部 |
| void seekdir(DIR *dir,off_t offset); //用来设置目录流目前的读取位置 |
| off_t telldir(DIR *dir); //返回目录流当前的读取位置 |
| int closedir(DIR *dir); //关闭目录文件 |
1.6.2 创建与删除目录相关的函数:
需要包含的头文件:
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
相关的函数API调用:
| int mkdir(const char *pathname, mode_t mode); //创建目录,mode是目录权限。 |
| int rmdir(const char *pathname); //删除目录。只能删除空目录 |
mkdir函数说明:mkdir()函数以mode方式创建一个以参数pathname命名的目录,mode定义新创建目录的权限。
返回值:若目录创建成功,则返回0;否则返回-1
mode方式:
| S_IRWXU | 00700权限,代表该文件所有者拥有读,写和执行操作的权限 |
| S_IRUSR(S_IREAD) | 00400权限,代表该文件所有者拥有可读的权限 |
| S_IWUSR(S_IWRITE) | 00200权限,代表该文件所有者拥有可写的权限 |
| S_IXUSR(S_IEXEC) | 00100权限,代表该文件所有者拥有执行的权限 |
| S_IRWXG | 00070权限,代表该文件用户组拥有读,写和执行操作的权限 |
| S_IRGRP | 00040权限,代表该文件用户组拥有可读的权限 |
| S_IWGRP | 00020权限,代表该文件用户组拥有可写的权限 |
| S_IXGRP | 00010权限,代表该文件用户组拥有执行的权限 |
| S_IRWXO | 00007权限,代表其他用户拥有读,写和执行操作的权限 |
| S_IROTH | 00004权限,代表其他用户拥有可读的权限 |
| S_IWOTH | 00002权限,代表其他用户拥有可写的权限 |
| S_IXOTH | 00001权限,代表其他用户拥有执行的权限 |
注意:创建目录之前需要先调用umask函数。
该函数原型:
| #include <sys/types.h> |
| #include <sys/stat.h> |
| mode_t umask(mode_t mask); |
函数说明:
umask()会将系统umask值设成参数mask&0777后的值,然后将先前的umask值返回。在使用open()建立新文件时,该参数mode并非真正建立文件的权限,而是(mode&~umask)的权限值。
例如,在建立文件时指定文件权限为0666,通常umask值默认为022,则该文件的真正权限则为0666&~022=0644,也就是rw-r--r--返回值此调用不会有错误值返回。返回值为原先系统的umask值。
因此,创建目录之前,需要先执行umask(0) 然后再调用mkdir函数。
示例:
| umask(0); |
| mkdir(argv[1],S_IRWXO); |
1.6.3 改变文件的访问权限
| #include <sys/stat.h> |
| int chmod(const char* path, mode_t mode); //mode形如:0777 |
path参数指定的文件被修改为具有mode参数给出的访问权限。
1.6.4 获取目录路径
原型为:
| #include <unistd.h> //头文件 |
| char *getcwd(char *buf, size_t size); //获取当前目录,相当于pwd命令 |
| char *getwd(char *buf); |
| char *get_current_dir_name(void); |
Getwd函数使用示例:
| char *cwd; |
| cwd = getcwd (NULL, 0); |
| if (!cwd) {perror (”getcwd”);exit (EXIT_FAILURE);} |
| printf (”cwd = %s\n”, cwd); |
| free (cwd);char cwd[BUF_LEN]; |
| if (!getcwd (cwd, BUF_LEN)) {perror (”getcwd”);exit (EXIT_FAILURE);} |
| printf (”cwd = %s\n”, cwd); |
get_current_dir_name函数使用示例:
| char *cwd; |
| cwd = get_current_dir_name ( ); |
| if (!cwd) {perror (”get_current_dir_name”);exit (EXIT_FAILURE);} |
| printf (”cwd = %s\n”, cwd); |
| free (cwd); |
getwd函数使用示例:
| char cwd[PATH_MAX]; |
| if (!getwd (cwd)) {perror (”getwd”);exit (EXIT_FAILURE);} |
| printf (”cwd = %s\n”, cwd); |
1.6.5 打开目录与读目录
| opendir函数打开目录; |
| readdir函数读取目录的内容,如果已经读取到目录末尾,又想重新开始读,则可以使用rewinddir函数将文件指针重新定位到目录文件的起始位置;closedir函数关闭目录 |
1.6.6 改变目录路径
| #include <unistd.h> |
| int chdir(const char *path); |
| int fchdir(int fd); |
Linux为改变当前目录,提供了两个函数,一个接受目录名,一个接受已经打开的目录文件描述符。
两个函数调用成功返回0,失败-1
注意: 这些改变目录的函数只是针对当前进程有效,Linux系统没有提供可以改变不同进程当前目录的机制。
示例1:
| char *swd; |
| int ret;/* save the current working directory */ |
| swd = getcwd (NULL, 0);if (!swd) {perror (”getcwd”);exit (EXIT_FAILURE);}/* change to a different directory */ |
| ret = chdir (some_other_dir); |
| if (ret) {perror (”chdir”);exit (EXIT_FAILURE);}/* do some other work in the new directory... // return to the saved directory */ |
| ret = chdir (swd); |
| if (ret) {perror (”chdir”);exit (EXIT_FAILURE);} |
| free (swd); |
示例2:
| int swd_fd; |
| swd_fd = open (”.”, O_RDONLY); |
| if (swd_fd == -1) |
| {perror (”open”);exit (EXIT_FAILURE);}/* change to a different directory */ |
| ret = chdir (some_other_dir); |
| if (ret) {perror (”chdir”);exit (EXIT_FAILURE);}/* do some other work in the new directory... // return to the saved directory */ |
| ret = fchdir (swd_fd); |
| if (ret) {perror (”fchdir”); |
| exit (EXIT_FAILURE);}/* close the directory’s fd */ |
| ret = close (swd_fd); |
| if (ret) {perror (”close”); |
| exit (EXIT_FAILURE); |
| } |
1.7 其他路径处理函数
1.7.1 获取目录名称
| #include <stdio.h> |
| int main() |
| {char *dirc, *basec, *bname, *dname; |
| char *path = "/etc/passwd"; |
| dirc = strdup(path); //字符串拷贝函数,自带malloc空间申请basec = strdup(path); |
| dname = dirname(dirc); |
| bname = basename(basec); |
| printf("dirname=%s, basename=%s\n", dname, bname); |
| return 0; |
| } |
| 运行结果: |
| [root@wbyq test]# ./a.outdirname=/etc, basename=passwd |
该函数还有对应的命令:
| [root@wbyq test]# dirname /work/123.c/work |
1.7.2 剔除目录名称
| #include <libgen.h> |
| char *basename(char *path); |
示例:
| #include <stdio.h> |
| int main() |
| { |
| printf("%s\n",basename("/worok/123.c")); |
| return 0; |
| } |
| 运行结果: |
| [root@wbyq test]# gcc 123.c |
| [root@wbyq test]# ./a.out123.c |
该函数还有相对应的命令: basename
示例:
| [root@wbyq test]# basename /work/123.c123.c |
以上两个函数路径使用总结:
| path dirname basename"/usr/lib" "/usr" "lib""/usr/" "/" "usr""usr" "." "usr""/" "/" "/""." "." "."".." "." ".." |
1.7.3 字符串拷贝函数
| #include <string.h> |
| char *strdup(const char *s); |
| char *strndup(const char *s, size_t n); |
| char *strdupa(const char *s); |
| char *strndupa(const char *s, size_t n); |
功 能: 将串拷贝到新建的位置处
strdup()在内部调用了malloc()为变量分配内存,不需要使用返回的字符串时,需要用free()释放相应的内存空间,否则会造成内存泄漏。
返回值:返回一个指针,指向为复制字符串分配的空间;如果分配空间失败,则返回NULL值。
示例:
| #include <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| int main() |
| { |
| char data[]="1234567890"; |
| char *p=strdup(data); |
| printf("p=%s\n",p); |
| free(p); |
| return 0; |
| } |