第四章:文件和目录

 


本章在第三章的基础上描述文件的属性,如大小、建立时间等。html

本章最后介绍对目录进行操做的各个函数。网络


 

 

1、stat()、fstat()、fstatat()和lstat()socket

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:文件路径名ui

buf:返回的stat结构体url

fd:文件打开函数返回的文件描述符spa

flags:标识符.net

返回值:成功返回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 };

 

 

2、文件类型

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() /* 网络套接字 */

 

 

3、文件访问权限

stat结构体中st_mode成员还包含有文件的访问权限,访问权限曾在第三章第二节有简单的演示。

为了打开任意类型的一个文件,则须要对该文件所在的父级以及父级的父级等目录具备执行权限。删除一个文件不须要对该文件有任何权限,只须要对被删除文件的父级目录具备写和执行权限便可。

 

进程每次打开、建立或删除一个文件时,内核就对该文件进行访问权限测试,一般的步骤是:

1. 先判断进程是不是超级用户,即ID是否为0,是则容许访问,不然执行第二步;

2. 再判断进程的有效用户ID是否等于文件的全部者ID,若是是而且被访问文件设定了适当的读写权限,则容许访问;不然执行第三步;

3. 而后判断进程有效组ID或者附加组ID是否等于文件的组ID,若是是而且被访问文件设定了适当的读写权限,则容许访问;不然执行第四步;

4. 最后查看文件的其余用户是否有适当权限访问文件,有则容许,不然判断结束、访问失败。

 

 

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


 

 

5、文件操做其余函数

权限屏蔽函数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。

 

 

6、目录相关函数

 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()关闭目录,这步也能够省略

 

若是咱们想要查看该目录以及其子目录的全部文件呢?

程序代码以下:

 1 #include <stdio.h>
 2 #include <dirent.h>
 3 #include <string.h>
 4 
 5 static void read_all_dir(char *path)  6 {  7     DIR *dir = opendir(path);  8     if (NULL == dir)  9         return; 10 
11     struct dirent *ent; 12 
13     while(ent = readdir(dir)) { 14         if ((0 == strcmp(ent->d_name, ".")) || 
15             (0 == strcmp(ent->d_name, ".."))) 16             continue; 17         if (8 == ent->d_type) { 18             printf("%s\n", ent->d_name); 19  } 20         else if (4 == ent->d_type) { 21             char buf[100] = { /* NULL */ }; 22             sprintf(buf, "%s/%s", path, ent->d_name); 23             printf("[%s]\n", ent->d_name); 24  read_all_dir(buf); 25  } 26  } 27  closedir(dir); 28 } 29 
30 int main() 31 { 32     read_all_dir("../"); 33 
34     return 0; 35 }

 

 

下一章  第五章:标准I/O库

相关文章
相关标签/搜索