【C/C++】文件夹的打开、遍历、删除、创建、关闭操作汇总
本文内容如下:
需要用到的头文件为:#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
DIR *fdopendir(int fd);
opendir()
函数打开一个指定路径name
的文件夹关联的流,并将该流以执行结果的方式返回给调用者。在默认情况下,该流指向文件夹下的第一个目录。fdopendir()
函数与opendir()
是相同的,只是该函数接收的方式是文件描述符fd
。fd
可以通过执行函数int dirfd(DIR *dirp);
获得。需要注意的是将fd
做为参数传递给fdopendir()
之后,则该fd
就不要在程序中的其它地方使用了。
以上两个函数正常执行时都会返回与文件夹相关联的流;否则返回NULL,错误的原因可以从errno
中获得。
struct dirent *readdir(DIR *dirp); NO Thread-Safe
int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result); Thread-Safe
执行readdir()
函数将返回文件夹流dirp
中的下一个条目,即文件夹下的子目录,重复执行时将会逐一返回文件夹下所有的子目录;一旦返回NULL则表示已经把所有的子目录都遍历过了或者出现了错误(可以通过errno
查看)。
返回的结果是这样的一个结构体:
1 | struct dirent { |
以上结构体出自 man ,在不同系统上会有各自不同的差别。
在上面的结构体中,文件名d_name
的限制长度256是包括字符串终止符’\0’的,所以在OS中,文件夹的命名最大字符数是255个。(在Mac中尝试是无法输入第256个字符的)
结构体中的d_type
用于标识当前的文件夹类型,支持的类型有:
1 | DT_BLK This is a block device. |
readdir_r()
是readdir()
的可重入实现版本,功能是一致的,但readdir_r()
是线程安全的。
执行readdir_r()
时遍历得到的子目录数据会存放在第二个参数entry
中,第三个参数result
指针指向子目录的entry
,且函数返回值返回0。当遍历到文件夹结束的位置时,返回值仍返回0,但第三个参数result
指针指向NULL。当函数执行错误时,则返回一个大于0的数字(即EBADF
)。
#####文件夹位置指针的操作
long telldir(DIR *dirp);
void seekdir(DIR *dirp, long loc);
void rewinddir(DIR *dirp);
DIR也是流的一种,对其进行读操作时也有位置指针的概念及操作。telldir()
可以获取当前的位置指针位置。返回值表示当前遍历的子目录是当前文件夹下的第几个目录(第0个是”.”当前目录,第1个是”..”上一级目录,所以从第2个开始计数。)seekdir()
可以操作位置指针跳转到指定的子目录序号loc
。rewinddir()
可以将位置指针恢复到流的起始位置。
#####遍历、过滤文件夹下的子文件(夹)
int scandir(const char *dirp, struct dirent ***namelist,
int (*filter)(const struct dirent *),
int (*compar)(const struct dirent **, const struct dirent **));
int scandirat(int dirfd, const char *dirp, struct dirent ***namelist,
int (*filter)(const struct dirent *),
int (*compar)(const struct dirent **, const struct dirent **));
scandir()
是遍历文件夹的另一种方式。本函数支持自定义遍历的过滤条件及结果排序,封闭了遍历的实现,执行后直接提供合法的目录信息,但该信息也只是目录名称而已。函数的返回结果是合法的子目录的个数;当函数执行出现错误时则返回-1且可以通过errno
去错误详情。dirp
指定要遍历的文件夹路径。namelist
用于指向遍历结果。可以看出该指针指向一个二维的字符数组,该二维数组存储着文件夹下的所有合法的文件名。*filter
是一个函数指针,该函数有一个参数const struct dirent *
是指在遍历过程中所遍历到的每一个子目录dirent
,filter
可以根据dirent
的类型、名称等信息来判定当前的dirent
是否为合法的子目录,合法则函数返回0,则该子目录的名称会被存储在namelist
中;否则返回非0,则该子目录被过滤掉。*compar
也是一个函数指针,该函数的两个参数都是const struct dirent *
用于决定两个子目录在namelist
中的顺序。
C的库中也默认提供了两个文件名称排序的方法:
int alphasort(const struct dirent **a, const struct dirent **b);
int versionsort(const struct dirent **a, const struct dirent **b);
alphasort()
的实现是把dirent
的名称用strcoll()
进行比较,排序的结果是按ASCII编码的值由小到大排序。versionsort()
的实现是把dirent
的名称strverscmp()
进行比较,排序的结果是也按ASCII编码的值由小到大排序,不同的是支持对名称中按数字序号的排序。举个例子对比alphasort()
与versionsort()
的不同:
alphasort: pc1 pc10 pc2 … pc9
versionsort: pc1 pc2 … pc9 pc10
很明显,versionsort()
的排序结果更符合普通人的阅读习惯。
scandirat()
是scandirat()
的扩展函数,主要区别就在于第一个参数dirfd
与第二个参数dirp
。
如果dirp
是一个绝对路径的字符串,则函数无视参数dirfd
,功能与scandir()
一致。
如果dirp
是一个相对路径的字符串,且参数dirfd
的值是AT_FDCWD (#include <fcntl.h>)
,则表示从应用程序当前的工作路径拼接上dirp
的相对路径所组成的绝对路径下去遍历;当dirfd
值不为AT_FDCWD
时而是一个代替文件夹的file descriptor
(参考dirfd(DIR*)
)时,则遍历的文件夹路径即为dirfd
所指向的文件夹再拼接上dirp
的相对路径所组成的绝对路径。
下面的示例代码演示了readdir
readdir_r
scandir
三种方式遍历文件夹的实现。
1 |
|
效果如下图:
int closedir(DIR *dirp);
closedir()
将关闭一个与文件夹相关联的流。执行本函数后,dirp
将不可再被使用。
int rmdir(const char *pathname);
删除指定路径下的文件夹。如果删除成功,则返回0;否则返回-1,并可通过errno
查看失败原因。
int mkdir(const char *pathname, mode_t mode);
int mkdirat(int dirfd, const char *pathname, mode_t mode);
mkdir()
函数用于创建文件夹,参数pathname
指定要创建的文件夹的绝对路径。参数mode
用于限定文件夹的文件权限(组)。该mode
将会OR操作后合成struct stat
中的st_mode
(详情)。文件权限(组)的mode
具体定义见下文的File Mode Bits(懒得翻译了,直接上英文)。所设置的文件权限(组)可以通过命令ls -l -a
查看。
如果函数正常执行并创建文件夹成功,则返回0;否则返回-1并且可以通过errno
查看错误详情。
扩展:直接mkdir(path, S_IRWXU| S_IRWXG| S_IRWXO),可生成的文件夹权限组是
drwxr-xr-x
而不是drwxrwxrwx
?
原因是:mkdir()
函数中指定的参数mode
值会和当前程序的umask
处理一下,具体处理为mode & ~unmask & 0777
才是最终的文件夹权限组。查看当前用户或程序的umask
可以在命令行终端上输入命令umask
可看。一般用户的umask
值为0022
。
mkdirat()
函数是mkdir()
的扩展,参数中dirfd
与pathname
的用法跟 scandir()
与scandirat()
的用法是一致的,这里就不重复说明了。
#####File Mode Bits:#####
S_IRWXU read, write, execute/search by owner
S_IRUSR read permission, owner
S_IWUSR write permission, owner
S_IXUSR execute/search permission, owner
S_IRWXG read, write, execute/search by group
S_IRGRP read permission, group
S_IWGRP write permission, group
S_IXGRP execute/search permission, group
S_IRWXO read, write, execute/search by others
S_IROTH read permission, others
S_IWOTH write permission, others
S_IXOTH execute/search permission, others
S_ISUID set-user-ID on execution
S_ISGID set-group-ID on execution
S_ISVTX on directories, restricted deletion flag
The bits defined by S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP, S_IROTH, S_IWOTH, S_IXOTH, S_ISUID, S_ISGID and S_ISVTX are unique.
S_IRWXU is the bitwise OR of S_IRUSR, S_IWUSR and S_IXUSR.
S_IRWXG is the bitwise OR of S_IRGRP, S_IWGRP and S_IXGRP.
S_IRWXO is the bitwise OR of S_IROTH, S_IWOTH and S_IXOTH.