回顾文件
我们之前认识文件只是在语言程度上理解,但是我们理解的不够彻底,要想真正理解文件要在os上理解。
简单代码认识
1 #include<stdio.h>
2 int main(){
3 FILE* fp=fopen("log.txt","w");
4 if(fp==NULL){
5 perror("fopen");
6 return -1;
7 }
8 fclose(fp);
9 return 0;
10 }
以w权限执行时,如果文件不存在就在当前路径下创建新文件。
我们在进行文件操作时,前提得是程序代码跑起来。
文件的打开与关闭都是cpu在执行我们的代码时执行到这一步才打开与关闭
那么如何向文件中写呢?
介绍函数:fprintf
以w权限时,默认打开文件的时候就会首先把目标文件清空。
文件打开方式
提炼对文件的理解
1. 打开文件本质就是进程打开文件(程序执行起来就是一个进程)。
task_struct---->struct xxx
struct xxx就是os内部对应的描述文件属性的结构体(类似pcb)
2. 文件没有被打开的时候在哪里?在磁盘(没有就创建)3. 进程能打开多个文件么(fopen)?可以
4. 系统中可不可以存在很多进程?当然可以,windows就有很多进程那么linux自然也有
5. 很多情况下,在os内部一定存在大量的被打开文件。那么os要不要把这些被打开的文件进行管理呢?
理解文件
a. 操作文件,本质是进程操作文件。进程和文件的关系
b. 文件刚开始是在磁盘上(外设设备,硬件),那么向文件中写入就是向硬件中写入,但是用户没权利直接向硬件中写入因为硬件的管理者是os,所以只能由os写入,所以os必须给我们提供系统调用接口,比如scanf/printf/fopen/fwrite/fread/fprintf/cin/cout(库函数)等我们用的c/c++/...都是对系统调用接口的封装(不同语言访问文件的方式有些不同)。即访问文件我们也可以用系统调用(open/write/close)
先用和认识系统调用的文件操作
标记位传参的理解
open:
close:
#include <unistd.h>
int close(int fd);//fd就是open返回的整数
注意man 2 close/open/write用2号页表查看系统调用接口
我们如果想按照我们预定的权限的话,加umask(0),这样程序会用我们自己的umask。但是自己设置一个umask系统也有一个umask那么程序执行谁的呢?就近原则,有自己的用自己的,没有的话用系统的
标志位flags是int类型32位比特位,那么可以用比特位来进行标志位的传递,这是os设计很多系统调用接口的常见方法。那么可以flags标志位传递理解为位图。
但是O_WRONLY | O_CREAT为什么大写呢?平常c/c++等大写的是宏,那么可以类推他俩也是宏
写入操作
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<string.h>
4 #include<sys/types.h>
5 #include<sys/stat.h>
6 #include<fcntl.h>
7 int main(){
8 umask(0);
9 int fp=open("log.txt",O_WRONLY|O_CREAT,0666);
10 if(fp<0){
11 perror("open");
12 return 1;
13 }
14 const char* ch="hello linux!";
15 write(fp,ch,strlen(ch));
16 return 0;
17
18 }
fd: 后面讲, msg:缓冲区首地址, strlen: 本次读取,期望写入多少个字节的数据。 返回值:实际写了多少字节数据
注意strlen在写的时候不需要再+1,\0是c语言的规定跟文件没关系,我们要把有效信息写入。
当然如果想截断清空的话可以加O_TRUNC:
当然也可以追加O_APPEND:
open返回值
由代码运行结果可知open函数返回值从3开始计数。那么0,1,2是什么呢?
0:标准输入 键盘
1:标准输出 显示器
2:标准错误 显示器
当然你也可以直接write(1,ch,strlen(ch));向显示器输出
通关理解
而现在知道,文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来 描述目标文件。于是就有了file结构体。表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针*files, 指向一张表files_struct,该表最重要的部分就是包涵一个指针数组,每个元素都是一个指向打开文件的指针!所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件 描述符,就可以找到对应的文件。
文件描述符的分配规则:在files_struct数组当中,找到当前没有被使用的 最小的一个下标,作为新的文件描述符。
那么问题来了,c语言为什么要这么做?
首先我们先理解,在进行文件操作时候可以使用系统调用也可以使用语言提供的操作方法。推荐语言提供的操作方法,因为系统不同(linux,windows,mac)那么系统的调用接口就不同,代码不具有跨平台性(使用linux代码无法在windows/mac运行)。
那么为什么语言提供的操作方法就可以呢?举例c语言,因为c语言本身的源代码-标准库的设计(通过条件编译,同一份源代码但是在不同平台运行不同代码),各个平台拥有各自的c标准库。所以所有的语言要想都具有跨平台性,则要求所有的语言对不同的平台的系统调用进行封装,则不同的语言封装的时候文件接口就有差别了。
进程控制xshell终端
ls /proc/
会显示很多蓝色文件夹,文件夹的名字是按照当前进程的pid来做的
显示这个进程的所有属性消息,也可以ls -l /proc/5903
那么我们也可以在通过左边终端写右边终端