前言
never give up!
无论如何,never give up!
正文
系统级 I/O
Linux shell下面创建的每个进程都有三个打开的文件
0:标准输入
1:标准输出
2:标准错误
文件的操作主要有:open,read,write,stat,dup2,close,lseek;
每个Linux文件都有一个类型:普通文件,目录,套接字等
(注套接字是网络编程上的东西,暑假我用socket写过一个服务端和客户端简单交流的CPP文件,之后会献上)
open函数
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(char* filename,int flags, mode_t mode);
open函数会返回一个文件描述符,由于Linux下面一切皆文件
flag参数
O_RDONLY:只读
O_WRONLY: 只写
O_RDWR: 可读可写
O_CREAT: 文件不存在,就创建一个它的截断的空文件。(就是创建一个新空白文件)
O_TRUNC: 如果文件已经存在,就截断它。(清空它)
O_APPEND: 在每次写操作前,设置文件位置到文件结尾处。
mode参数
S_IRUSR:使用者(拥有者)能够读这个文件
S_IWUSR:使用者(拥有者)能够写这个文件
S_IXUSR:使用者(拥有者)能够执行这个文件
S_IRGRP:拥有者所在组的成员能够读这个文件
S_IWGRP:拥有者所在组的成员能够写这个文件
S_IXGRP:拥有者所在组的成员能够执行这个文件
S_IROTH:其他人(任何人)能够读这个文件
S_IWOTH:其他人(任何人)能够写这个文件
S_IXOTH:其他人(任何人)能够执行这个文件
这里的mode用一个三位的八进制数进行标识,也就意味着一共九位01二进制来表示是否可读,可写,可执行。
关闭文件
#include <unistd.h>
int close(int fd);
读写文件
#include <unistd.h>
ssize_t read(int fd,void *buf,size_t n);
ssize_t write(int fd,const void *buf,size_t n);
read函数从描述符为fd的文件的当前位置复制最多n个字节到位置buf。三种返回值:-1出错,0表示EOF,或者是读取到的字节的个数。
write函数从内存buf出至多复制n个字节到描述符为fd的当前文件位置。
读取元数据
调用stat()函数或者fstat()函数
作用为获取文件信息
返回值,成功返回1,失败返回-1
#include <unistd.h>
#include <sys/stat.h>
int stat(const char*filename,struct stat* buf);
int fstat(int fd,struct stat* buf);
stat函数以一个文件名作输入,可以查看到文件的各种数据
struct stat
{
dev_t st_dev; /* ID of device containing file */文件使用的设备号
ino_t st_ino; /* inode number */ 索引节点号
mode_t st_mode; /* protection */ 文件对应的模式,文件,目录等
nlink_t st_nlink; /* number of hard links */ 文件的硬连接数
uid_t st_uid; /* user ID of owner */ 所有者用户识别号
gid_t st_gid; /* group ID of owner */ 组识别号
dev_t st_rdev; /* device ID (if special file) */ 设备文件的设备号
off_t st_size; /* total size, in bytes */ 以字节为单位的文件容量
blksize_t st_blksize; /* blocksize for file system I/O */ 包含该文件的磁盘块的大小
blkcnt_t st_blocks; /* number of 512B blocks allocated */ 该文件所占的磁盘块
time_t st_atime; /* time of last access */ 最后一次访问该文件的时间
time_t st_mtime; /* time of last modification */ /最后一次修改该文件的时间
time_t st_ctime; /* time of last status change */ 最后一次改变该文件状态的时间
};
下面的这个代码
/* $begin statcheck */
#include "csapp.h"
int main (int argc, char **argv)
{
struct stat stat;
char *type, *readok;
/* $end statcheck */
if (argc != 2) {
fprintf(stderr, "usage: %s <filename>\n", argv[0]);
exit(0);
}
/* $begin statcheck */
Stat(argv[1], &stat);
if (S_ISREG(stat.st_mode)) /* Determine file type */
type = "regular";
else if (S_ISDIR(stat.st_mode))
type = "directory";
else
type = "other";
if ((stat.st_mode & S_IRUSR)) /* Check read access */
readok = "yes";
else
readok = "no";
printf("type: %s, read: %s\n", type, readok);
exit(0);
}
该程序用来查看文件类型,和访问权限
S_ISREG(m)是否为普通文件
S_ISDIR(m)是否为目录文件
S_ISSOCK(m)是否为网络套接字
共享文件![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/3df9b1c9142c0a979e6f955dcc595141.png)
1.每个进程对应一张打开文件描述符表,这是进程级数据结构,也就是每一个进程都各自有这样一个数据结构;
2.内核维持一张打开文件表,文件表由多个文件表项组成,这是系统级数据结构,也就是说这样的数据结构是针对于整个内核而言的,每个进程都可共享的;3.每个打开的文件对应一个i节点(i-node)数据结构(Linux下只有i节点没有v节点),由于这是每一个打开的文件与之对应的,因此这也是一个系统级数据结构,存在于内核中,非进程所独有。
(1)每一个打开文件实际上就是用一个file结构体进行描述的
(2)内核为所有的打开文件维持一张文件表,每个文件表项包含:
a.文件状态标志(读、写、同步、阻塞等)
b.当前文件偏移量
c.指向该文件的v节点表项的指针
总结
I/O重定向
例子:
ls>1.txt
shell加载执行ls程序,将标准输出重定向到1.txt
而后是dup2()函数
#include "csapp.h"
int main(int argc, char *argv[])
{
int fd1, fd2, fd3;
char c1, c2, c3;
char *fname = argv[1];
fd1 = Open(fname, O_RDONLY, 0);
fd2 = Open(fname, O_RDONLY, 0);
fd3 = Open(fname, O_RDONLY, 0);
dup2(fd2, fd3);
Read(fd1, &c1, 1);
Read(fd2, &c2, 1);
Read(fd3, &c3, 1);
printf("c1 = %c, c2 = %c, c3 = %c\n", c1, c2, c3);
Close(fd1);
Close(fd2);
Close(fd3);
return 0;
}
得到c1=a,c2=a,c3=b
#include <unistd.h>
int dup2(int oldfd,int newfd);
dup2函数做的其实就是用oldfd的文件表表项替换掉newfd的文件表表项,此外如果newfd是打开的状态的话,会需要先关闭掉newfd。
dup()函数
int dup(int oldfd);
dup()函数
新建一个文件项
题目:
#include "csapp.h"
int main(int argc, char *argv[])
{
int fd1, fd2, fd3;
char *fname = argv[1];
fd1 = Open(fname, O_CREAT|O_TRUNC|O_RDWR, S_IRUSR|S_IWUSR);
Write(fd1, "pqrs", 4);
fd3 = Open(fname, O_APPEND|O_WRONLY, 0);
Write(fd3, "jklmn", 5);
fd2 = dup(fd1); /* Allocates new descriptor */
Write(fd2, "wxyz", 4);
Write(fd3, "ef", 2);
Close(fd1);
Close(fd2);
Close(fd3);
return 0;
}
/*abcde.txt
pqrswxyzef
*/
先写出pqrs,fd3追加模式,写成jklmn五个字符,所以现在是pqrsjklmn,dup得到新的,光标停在pqrs后,
然后fd2,wxyz覆盖jklm,最后得到ef
总结为pqrswxyznef
后言
rethink,rethink,rethink