需要掌握:操作文件,本质:进程操作文件。进程和文件的关系
向文件中写入,本质上向硬件中写入->用户·没有权利直接写入->操作系统是硬件的管理者,我们可以通过操作系统往硬件写入->操作系统必须提供系统调用(默认操作系统不相信任何人)
我们使用的fopen/fwrite/fread/fprintf/scanf/printf/cin/cout/实际上都是对系统调用的接口的封装.
系统调用函数open
头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
open函数
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
第一个open函数的第一个参数是文件名,第二个参数是打开方式,
其中我们要了解的打开方式有
O_WRONLY//只读方式
O_CREAT//没有该文件就创建
O_APPEND//追加
O_TRUNC//覆盖式写入
因为要用到close函数关闭文件,
close函数
头文件
#include <unistd.h>
int close(int fd);
有一个疑问,为什么他的 参数是int类型的,因为对应的打开方式可以是int 32中任何一位为1并且和其他区分开来,然后需要多个功能的话,按位或就可以,这是操作系统调用接口的常见方法
1.只写和没有该文件就创建
1 #include<stdio.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 int main()
7 {
8 int fd=open("log.txt", O_WRONLY| O_CREAT|O_APPEND);
9 if(fd<0)
10 {perror("open");
11 return 1;}
12 close(fd);
13 return 0;
14
15 }
O_WRONLY| O_CREAT
我们发现当前目录下没有我们要的“log.txt”
当我们运行这个程序后,发现出现了该文件
为了测试追加功能,我们通过vim往log.txt里面写入点东西
修改打开方式为只写和追加,所以修改参数2为
O_WRONLY|O_APPEND
但是我们发现log.txt这个文件的权限怎么不对呀,这里是因为如过用第一个open函数的话,就必须是已经创建好的文件,就已经有了权限,要不然就只能用第二个open函数,第二个open函数的第三个参数就是要设置的掩码值,所以我们使用第二个open函数
#include<stdio.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 int main()
7 {
8 int fd=open("loog.txt", O_WRONLY| O_CREAT|O_APPEND,0666); //设置log.txt文件掩码为0666
9 if(fd<0)
10 {perror("open");
11 return 1;}
12 close(fd);
13 return 0;
14
15 }
但是这里的权限是664呢,因为我们可以通过unmask来查看对应的默认掩码
我们可以将默认掩码在函数内设置为0
这段代码修改了掩码为0,并且修改其文件名
此时我们就可以修改我们的loog.txt文本文件了
使用打开方式
O_WRONLY|O_APPEND
此时我们就用到了write函数,
头文件
#include <unistd.h>
函数
ssize_t write(int fd, const void *buf, size_t count);
函数第一个参数是文件描述符,对应你打开的文件,待会在讲这个fd,文件描述符,
第二个参数是你要写入的字符串,第三个参数是要写入字符串的大小
1 #include<stdio.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 int main()
7 {
8 umask(0);
9
10 int fd=open("looog.txt", O_WRONLY|O_APPEND,0666);
11
12 if(fd<0)
13 {perror("open");
14 return 1;}
15 char buf[]="hello world";
16 write(fd, buf,sizeof(buf));
17 close(fd);
18 return 0;
19
20 }
覆盖式写入
第二个参数修改为:
O_WRONLY| O_TRUNC
1 #include<stdio.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 int main()
7 {
8 umask(0);
9
10 int fd=open("looog.txt", O_WRONLY| O_TRUNC,0666);
11
12 if(fd<0)
13 {perror("open");
14 return 1;}
15 char buf[]="hello world";
16 write(fd, buf,sizeof(buf));
17 close(fd);
18 return 0;
19
20 }
除了上面的方法给文件写入数据,我们还可以通过echo写入数据
我们发现是覆盖式写入
我们发现是追加式写入
文件操作符
我们刚才使用了open函数,和write函数,里面open函数返回的是一个fd,write的第一个参数是fd,这就是我们要提到的文件操作符
为了讲清文件操作符这个概念
我们可以先来说说操作系统是如何进行文件的写入和读呢?
在我们启动进程时,默认操作系统已经帮我们打开
标准输入流:0(对应的文件标识符)—键盘
标准输出流:1(对应的文件标识符)—显示器
标准错误流:2(对应的文件标识符)—显示器
我们可以把这些外设也当成文件(linux一切皆文件)
如果是文件,当我们使用的时候,也会给他创建pcb结构来管理外设
在操作系统内,系统在访问文件的时候,只认文件描述符fd
open函数在干什么呢??
1.创建file对应的pcb管理文件属性
2.开辟文件缓冲区的空间,将文件数据加载到文件缓冲区去(延后)
3.查进程文件的文件描述表
4.将对应文件的地址填入到指针数组中去
5.返回下标
文件操作符的本质是什么呢?
内核的进程:文件映射关系的数组下标
c语言如何通过FILE*访问文件呢?
1 #include<stdio.h>
2 int main()
3 {
4 FILE* fp=fopen("hot.txt","w");
5 if(NULL==fp)
6 {
7 perror("fopen error");
8 return 1;
9
10
11
12 }
13 fprintf(fp,"hello world");
14 fclose(fp);
15 return 0;
16 }
实际上FILE是一个c语言的一个结构体类型,里面封装了文件标识符fd
gcc -E file.c -o file.i//预处理完就停下,头文件展开
在stdio.h头文件里面
1 #include<stdio.h>
2 int main()
3 {
4 printf("输入流:%d\n",stdin->_fileno);//对应结构体里面封装了文件的文件标识符
5 printf("输出流:%d\n",stdout->_fileno);
6 printf("错误流:%d\n",stderr->_fileno);
7
8
9
10
11
12
13
14
15 }
接着打开的文件的文件标识符就从3开始往后
终端也是文件
我们复制ssh的渠道,左边为另一个终端
1 #include<stdio.h>
2 #include <unistd.h>
3 #include <sys/types.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <fcntl.h>
7
8 int main()
9 {
10 while(1)
11 {
12 printf("pid:%d\n",getpid());
13
14
15
16
17
18 }
19 //int fd=open("/dev/pts/0",O_WRONLY| O_TRUNC,0666);
20 //if(fd<0)
21 // {perror("error");}
22 //char arr[]="hello wokao";
23 //write(fd,arr,sizeof(arr));
24 //close(fd);
25
26 }
/proc/目录下存在着正在运行的进程的pid
1 #include<stdio.h>
2 #include <unistd.h>
3 #include <sys/types.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <fcntl.h>
7
8 int main()
9 {int fd=open("/dev/pts/0",O_WRONLY| O_TRUNC,0666);
10 if(fd<0)
11 {perror("error");}
12 char arr[]="hello wokao";
13 write(fd,arr,sizeof(arr));
14 close(fd);
15
16 }
把终端当文件写入
c语言为什么支持跨平台性
支持系统调用,也可以使用语言提供文件方法系统不同,可能导致系统调用的接口可能不一样,导致代码不具有跨平台性,所以所有的语言都想具有跨平台性,所以所有的语言要对平台的系统调用进行封装,不同语言封装,文件接口就有差别了