目录
编辑 系统接口进行文件访问
open 接口介绍
文件描述符fd
重定向
缓冲区
1、缓冲区是什么?
2、为什么要有缓冲区?
3、怎么办?
我们先来复习一下,c语言对文件的操作:
C默认会打开三个输入输出流,分别是stdin, stdout, stderr
1 #include<stdio.h>
2
3 int main()
4 {
5 FILE *fp=fopen("log.txt","w");
6 if(fp==NULL)
7 {
8 perror("error!");
9 return 1;
10 }
11 fprintf(fp,"hello,%d,%s\n",10,"sxh");
12 fclose(fp);
13 return 0;
14 }
系统接口进行文件访问
操作文件,除了上述C接口(当然,C++也有接口,其他语言也有),我们还可以采用系统接口来进行文件访问;
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
int main()
{
umask(0);
int fd =open("log.txt",O_WRONLY | O_CREAT |O_TRUNC,0666);
if(fd<0)
{
perror("open");
return 1;
}
//const char *message ="hello Linux!\n";
const char * message ="aaaa\n";
write(fd,message,strlen(message));
close(fd);
}
open("log.txt",O_WRONLY | O_CREAT |O_TRUNC,0666);:以写方式打开,不存在就创建,存在就先清空!相当于c语言中的 “w” 方式;
open 接口介绍
open man 2 open
#includ e <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode)
int creat(const char *pathname, mode_t mode);pathname:要打开或创建的目标文件
flags: 打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成; 常见的参数有:
O_RDONLY: 只读打开
O_WRONLY: 只写打开
O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
O_APPEND: 追加写mode: mode 只有 当 在 flags 中使用 O_CREAT 时才有效 , 否则被忽略.
返回值:
成功:新打开的文件描述符
失败:-1
文件描述符fd
我们通过系统调用I/O打开一个文件的返回值,就是文件描述符:
int fd = open("log.txt",O_WRONLY | O_CREAT |O_TRUNC,0666);
这里fd就是log.txt的文件描述符;
如果我们同时打开三个文件,并把这三个文件的文件描述符打印出来,会发现:
文件描述符是从3开始的,那0、1、2呢?
Linux进程默认情况下会有3个缺省打开的文件描述符:分别是标准输入0, 标准输出1, 标准错误2.
0,1,2对应的物理设备一般是:键盘,显示器,显示器
根据上述的图,我们可以知道:
open干什么?
1、创建file
2、开辟文件缓冲区的空间,加载文件数据(延后)
3、查看进程的文件描述符表
4、file地址,填入对应的表下标中
5、返回下标
重定向
看一下下面的代码:
1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/stat.h>
4 #include<fcntl.h>
5 #include<unistd.h>
6 #include<string.h>
7 #include<stdlib.h>
8 const char *filename="log.txt";
9
10 int main()
11 {
12 //close(0);
13 close(1);
14 //close(2);
15 int fd =open(filename,O_CREAT | O_WRONLY | O_TRUNC,0666);
16 if(fd<0)
17 {
18 perror("open");
19 return 1;
20 }
21 printf("printf,fd:%d\n",fd);
22 fprintf(stdout,"fprintf,fd:%d\n",fd);
23
24 fflush(stdout);
25
26
27 close(fd);
28 return 0;
29
30 }
先看现象:
1、如果我们关闭的是0:打印出来的log.txt的文件描述符是0;关闭的是2,则打印出来的文件描述符是2;关闭的是1,则不会显示出来;因为文件描述符1表示的是显示器,而我们把显示器关掉了自然打印不出来;
2、我们会在log.txt中打印出printf和fprintf的内容:
现象解释:
文件描述符规则:查看自己的文件描述表,分配最小的没有使用的文件描述符;
由于我们把显示器给关掉了,那么文件描述符1就是最小的没有使用的,这样log.txt就会被分配1为文件描述符;这其实就是一个重定向操作;
看下面的图:
一开始fd_array[1]指向的是显示器,由于close(1),加上open log.txt这样fd_array[1]指向的就是log.txt;
因为重定向的本质是在内核中改变文件描述符特点下标的内容,与上层无关;
fprintf()/printf() --->stdout --->struct FILE --->stdout ---->_fileno ==1;
所以fprintf()/printf() 看的就是_fileno ==1;由于重定向后log.txt的fd为1 ,自然fprintf()/printf()的内容打印到log.txt中;
如果我们一直用这种手动重定向的方式,比较麻烦;可以用系统调用:dup2()
看一下代码:
1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/stat.h>
4 #include<fcntl.h>
5 #include<unistd.h>
6 #include<string.h>
7 #include<stdlib.h>
8 const char *filename="log.txt";
9
10 int main()
11 {
12 int fd = open(filename,O_CREAT | O_WRONLY | O_TRUNC,0666);
13 //dup2(fd,1);
14
15 printf("hello world,fd:%d\n",fd);
16 fprintf(stdout,"hello world\n");
17 fflush(stdout);
18 close(fd);
19 return 0;
20 }
上述的代码运行结果:会直接打印到显示器上;
如果把dup2(fd,1);复原:显示器上不会显示,而是在log.txt上显示
其实本质就是将fd覆盖1 指向下标的内容;
缓冲区
1、缓冲区是什么?
缓冲区就是一段内存空间
2、为什么要有缓冲区?
给上层提供高效的IO体验,间接提高整体效率
3、怎么办?
a、刷新策略
1、立即刷新 fflush(stdout)(c语言的刷新)、fsync(fd)(系统调用的刷新)
2、行刷新 (显示器)
3、全缓冲 (缓冲区写满,才刷新,普通文件)
b、特殊情况
进程退出,系统会自动刷新
强制刷新