本章在第三章的基础上描述文件的属性,如大小、创建时间等。
本章最后介绍对目录进行操作的各个函数。
一、stat()、fstat()、fstatat()和lstat()
stat系列函数用于返回文件的属性信息,如文件类型、大小、所有者、访问修改时间等。函数声明如下:
1 /* 文件属性查看函数 */ 2 #include <sys/stat.h> 3 4 int stat(const char *pathname, struct stat *buf); 5 int fstat(int fd, struct stat *buf); 6 int lstat(const char *pathname, struct stat *buf); 7 int fstatat(int fd, const char *pathname, struct stat *buf, int flags); 8 9 /* 例子 */ 10 struct stat st; 11 fstat(fd, &st); 12 char *buf; 13 14 if (S_ISREG(st.st_mode)) 15 buf = "regular"; /* 普通文件 */ 16 else if (S_ISDIR(st.st_mode)) 17 buf = "directory"; /* 目录 */ 18 else if (S_ISCHR(st.st_mode)) 19 buf = "character special"; /* 字符文件 */ 20 else if (S_ISBLK(st.st_mode)) 21 buf = "block special"; /* 块文件 */ 22 else if (S_ISFIFO(st.st_mode)) 23 buf = "fifo"; /* 管道文件 */ 24 /* 25 else if (S_ISLINK(st.st_mode)) 26 buf = "link"; /* 链接文件,使用fstat()无法识别 */ 27 */ 28 else if (S_ISSOCK(st.st_mode)) 29 buf = "socket"; /* 网络套接字 */ 30 else 31 buf = "unknow mode"; 32 33 printf("%s\n", buf);
函数参数以及返回值:
pathname:文件路径名
buf:返回的stat结构体
fd:文件打开函数返回的文件描述符
flags:标识符
返回值:成功返回0;出错返回-1。
上面函数返回的stat结构体各个实现可能存在差异,但它们都至少具备下列的信息:
1 struct stat { 2 mode_t st_mode; // 文件类型和访问权限 3 ino_t st_ino; // 指向数据块的节点的编号 4 dev_t st_dev; // 设备号 5 dev_t st_rdev; 6 nlink_t st_nlink; // 硬链接数 7 uid_t st_uid; // 用户ID 8 gid_t st_gid; // 用户组ID 9 off_t st_size; 10 struct timespec st_atim; // 数据访问时间 11 struct timespec st_mtim; // 数据修改时间 12 struct timespec st_ctim; // 属性修改时间 13 blksize_t st_blksize; // 最好的IO块大小 14 blkcnt_t st_blocks; 15 };
二、文件类型
UNIX系统中的文件大多数是普通文件和目录,但也存在其他类型的文件,其分类如下:
普通文件(regular file):包含数据的常规文件,数据可以是文本类型的,也可以是二进制的。
目录文件(directory file):它是一个目录,保存目录相关的信息。
块设备文件(block special file):这种文件提供对硬件(如磁盘)带缓冲的访问。
字符设备文件(regular file):这种文件提供对硬件(如磁盘)不带缓冲的访问。
FIFO:这种文件用于进程间通信。
套接字文件(regular file):这种文件用于网络间通信。
符号连接(regular file):类似Windows系统的快捷方式,指向另外一个文件。
以上文件类型的信息存储在前面说明的stat结构体中st_mode成员中的。正如我所给出的上面的例子,st_mode成员的读取是利用系统提供的宏函数进行的。在此我总结以下上文例子中的宏函数:
S_ISREG() /* 普通文件 */ S_ISDIR() /* 目录 */ S_ISCHR() /* 字符文件 */ S_ISBLK() /* 块文件 */ S_ISFIFO() /* 管道文件 */ S_ISLINK() /* 链接文件 */ S_ISSOCK() /* 网络套接字 */
三、文件访问权限
stat结构体中st_mode成员还包含有文件的访问权限,访问权限曾在第三章第二节有简单的演示。
为了打开任意类型的一个文件,则需要对该文件所在的父级以及父级的父级等目录具有执行权限。删除一个文件不需要对该文件有任何权限,只需要对被删除文件的父级目录具有写和执行权限即可。
进程每次打开、创建或删除一个文件时,内核就对该文件进行访问权限测试,通常的步骤是:
1. 先判断进程是否是超级用户,即ID是否为0,是则允许访问,否则执行第二步;
2. 再判断进程的有效用户ID是否等于文件的所有者ID,如果是并且被访问文件设定了适当的读写权限,则允许访问;否则执行第三步;
3. 然后判断进程有效组ID或者附加组ID是否等于文件的组ID,如果是并且被访问文件设定了适当的读写权限,则允许访问;否则执行第四步;
4. 最后查看文件的其他用户是否有适当权限访问文件,有则允许,否则判断结束、访问失败。
四、access()和faccessat()
access()和faccessat()函数可用于判断当前用户是否具有访问某个文件的权限。函数声明如下:
1 /* 权限检测函数 */ 2 #include <unistd.h> 3 4 int access(const char *pathname, int mode); 5 int faccessat(int fd, const char *pathname, int mode, int flags); 6 7 /* 例子 */ 8 if (access("a.txt", R_OK) == 0) /* 是否有读权限 */ 9 printf("a.txt read ok\n"); 10 if (access("a.txt", W_OK) == 0) /* 是否有写权限 */ 11 printf("a.txt write ok\n"); 12 if (access("a.txt", X_OK) == 0) /* 是否有执行权限 */ 13 printf("a.txt execute ok\n");
函数参数以及返回值:
pathname:文件路径名
mode:模式,包含有R_OK、W_OK、X_OK和F_OK
flags:标识符
返回值:有权限返回0
五、文件操作其他函数
权限屏蔽函数umask(),用于设置创建新文件时的权限屏蔽字,对于修改文件权限时权限屏蔽字没有效果,函数声明如下:
#include <sys/stat.h> mode_t umask(mode_t mask); /* 例子 */ mode_t old = umask(0222); /* 如果原来的权限是0777,那么最终的结果是077 - 0222 = 0555,old返回原来的权限 */ umask(old); /* 恢复权限 */
chmod()、fchmod()和fchmodat()这三个函数用于更改文件的访问权限。函数声明如下:
1 #include <sys/stat.h> 2 3 int chmod(const char *file, mode_t mode); 4 int fchmod(int fd, mode_t mode); 5 int fchmodat(int fd, const char *file, mode_t mode, int flag); 6 7 /* 例子 */ 8 fchmod(fd, 0666); /* 更改权限为0666 */
权限改变成功则返回0,失败返回-1。
六、目录相关函数
1 #include <dirent.h> 2 3 /* 打开一个目录 */ 4 DIR *opendir(const char *name); // 成功返回指针,失败返回NULL 5 DIR *fdopendir(int fd); // 成功返回指针,失败返回NULL 6 7 /* 读取目录中的内容,如文件、子目录 */ 8 struct dirent *readdir(DIR *dirp); // 成功返回指针,失败返回NULL 9 10 /* 让目前的读取位置还原到开头的读取位置 */ 11 void rewinddir(DIR *dirp); 12 13 /* 设置相对于开头偏移值为pos的读取位置 */ 14 void seekdir(DIR *dirp, long int pos); 15 16 /* 关闭目录 */ 17 int closedir(DIR *dirp); // 成功时返回0,失败返回-1 18 19 /* 例子 */ 20 DIR* dir = opendir("../"); 21 struct dirent* ent; 22 while(ent=readdir(dir)) // 1 读, 2 =,3 判断ent是否为0 23 { 24 printf("%d, %s\n", ent->d_type, ent->d_name); 25 } // d_tpye == 4 的是目录 26 closedir(dir);
读某个目录内容(子项)的步骤:
1. opendir()返回目录指针
2. 循环调用readdir(),逐一读取每个子项
3. closedir()关闭目录,这步也可以省略
原文地址:https://www.cnblogs.com/Lioker/p/10682870.html