系统文件I/O
先从代码中来看:
//写文件
int main()
{
umask(0);
int fd=open("myfile",O_WRONLY|O_CREAT,0644);
if(fd<0)
{
perror("open");
return 1;
int count=5;
const char*msg="hello world\n";
int len=strlen(msg);
while(count--)
{
write(fd,msg,len);
}
close(fd);
return 0;
}
//读文件
int main()
{
int fd=open("myfile",O_WRONLY);
if(fd<0)
{
perror("open");
return 1;
}
const char*msg="hello world\n";
char buf[1024];
while(1)
{
ssize_t s=read(fd,buf,strlen(msg));
if(s>0)
{
printf("%s",buf);
}
else{
break;
}
}
close(fd);
return 0;
}
open()
int open(const char*pathname,int flags)
int open(const char*pathname,int flags,mode_t mode)
//pathname:要打开或创建的目标文件
//flags:打开文件时,可以传入多个参数选项,可以用虾米一个或多个常量进行“或”运算,构成flags。
参数:
O_RDONLY:只读打开
O_WRONLY:只写打开
O_RDWR:读写打开
这三个常量有些只能有一个
O_CREAT:若文件不存在,则需要创建,需要使用mode选项,指明新文件的权限
O_APPEND:追加写
返回值:
成功:新打开文件的描述符
失败:-1
系统调用和库函数
刚刚使用的read,write,close,open都属于系统提供的接口,称之为系统调用接口
fopen,fclose,fread,fwrite都是C标准库中的函数,称之为库函数
系统调用:指运行在用户空间的应用程序向操作系统内核请求某些服务的调用过程。
库函数:是由用户或组织自己开发的,具有一定功能的函数集合,是对系统调用的封装。
文件描述符(fd)
文件描述符就是非负的整数,他是一个索引值,指向内核中打开文件的记录表。
0&1&2
1. LINUX进程默认情况下会有三个缺省打开的文件描述符,分别是标准输入(stdin)0,标准输出(stdout)1,标准错误(stderr)2
2. 0,1,2对应的物理设备一般是:键盘、显示器、显示器
由上图我们可知,当我们要打开新的文件时,操作系统在内存中要创建相对应的数据结构来描述目标文件,产生了file结构体,表示一个已经打开的文件对象,而当进程执行open系统调用,所以需要将进程和文件关联起来,因此每个进程都有一个指针*files,指向一张表files_strucrt,该表最重要的一部分就是包含了一个指针数组,每个元素都是一个指向打开文件的指针,所以本质上,文件描述符就是该数组的下标。
文件描述符分配规则
在file_struct数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。
重定向
int main()
{
close(1);
int fd=open("myfile",O_WRONLY|O_CREAT,00644);
if(fd<0){
perror("open");
return 1;
}
prinitf("fd:%d\n",fd);
fflush(stdout);
close(fd);
exit(0);
}
通过上面的代码我们可以看出来,本该输出到显示器上的内容,输出到了文件myfile中,并且其中fd为1,这种现象称之为重定向,常见的重定向有>,>>,<
重定向的本质:
由上图我们可以看出,当stdout访问底层文件时候,找的还是fd==1的文件,此时fd=1所表示的内容已经是myfile的地址,不再是显示文件的地址,所以,输出的所有消息都会被写入到myfile文件中,从而完成输出重定向。
在file结构体中最重要的两个成员变量:文件描述符,缓冲区大小
缓冲区
1.全缓冲:当缓冲区数据填满时刷新
2.行缓冲:当遇到/n时立即刷新
3.无缓冲:直接输出