Linux——基础IO(上)|语言层面如何访问文件|什么是一切皆文件|C语言文件操作复习|什么是当前路径|系统接口的使用|open|close|write|read|文

目录

 语言层面如何访问文件 

什么是一切皆文件 

C语言文件操作复习 

什么是当前路径 

系统接口的使用 

open|close 

write 

read

 文件描述符

fd的理解 


 语言层面如何访问文件 

文件=内容+属性(也是数据)

对文件的所有操作,俩种:a.对内容b.对属性

文件在磁盘(硬件)上放着,我们访问文件,先写代码->编译->exe->运行->访问文件:本质是进程在访问文件

进程访问文件时需要通过接口访问的,接口分为语言接口和系统接口

向硬件中写入时,只有操作系统有权利写。当普通用户也想写入的时候,必须让OS提供接口,这个接口是文件类的系统调用接口(这个接口在软件层),系统调用接口使用比语言上的接口要难一些。

语言会对这些系统调用接口封装,让我们用起来更舒服一些,不同的语言有不同的语言级别的文件访问接口(都不一样)。

系统调用接口只有一套,虽然语言封装不一样,但底层使用的系统接口都是一样的。

大多数语言可以跨平台,如果语言不提供对文件的系统接口的封装,那么所有访问文件的操作,都必须使用OS的接口,windows和linux接口就不一样,当使用语言时候,如果要访问文件,一旦使用系统接口编写文件代码,就无法在其它平台运行,所以语言级别的接口要封装,语言会把所有平台的代码都实现一遍,保证跨平台性。

什么是一切皆文件 

 Linux认为一切皆文件,硬件等设备也是文件。

 显示器:printf/cout->本质是写入output

键盘:scanf/cin->本质是读input

读写都是站在内存的角度。

站在系统的角度,能够被input读取,或者能够output写出的设备就叫文件,文件也包括显示器,键盘,网卡,声卡,显卡,磁盘。几乎所有的外设,都可以称之为文件

C语言文件操作复习 

 底行模式输入:!man fopen ,可查看使用手册

 sdtio,std:标准,io:input/output

fopen(要打开的文件,打开方式)

mode是一种模式

 w+读写打开,如果文件不存在,文件就先会被创建

w会清空文件再写或创建一个

a/a+:从文件末尾开始写(追加重定向/输出重定向)

 运行程序

 加上\n

 查看,我们发现之前的代码被覆盖掉了

写入的时候不需要给strlen(s1)加1,不需要给\0保留位置,因为\0结尾是C语言的规定,文件不需要遵守C语言的规定,文件保存的是有效数据,\0不算有效数据,是C语言规定的文件结束的标识符

我们注释掉这些内容

 此时进行查看,log.txt中没有任何内容,也就是我们之前的文件被屏蔽掉了

 这说明以w方式打开文件的时候,先做的不是写入,而是清空

echo+>+内容+文件名,可在文件中写入内容

 如果要清空文件中的内容输入>文件名,即可清空

 以a的方式打开

 

 每运行一次,就追加一次内容

 读取文件

 

 写一个cat命令

 

 fopen以w方式打开文件,默认先清空文件(注意:在fwrite之前)

fopen以a打开,追加新内容

C语言会默认打开这三个流

stdout:标准输出流

stdin:标准输入流

stderr:标准错误流

这三个是文件指针 

标准输入:键盘                       标准输出:显示器                      标准错误:显示器

在C语言角度,我们创建的文件是FILE*,这三个流也是FILE*,说明一切皆文件。

什么是当前路径 

 

当我们把myfile拷贝到上一级目录之后运行,我们发现上一级目录也有log.txt

log.txt是进程创建的

写一个死循环进行观察

 myfile的pid是11174

 我们可以看到这俩个东西

 exe程序在磁盘上所对应的路径

cwd当前进程的工作目录

我们把myfile拷贝到上一级目录,然后运行

 当一个进程运行起来的时候,每个进程都会记录自己当前所处的工作路径

当前路径,进程运行起来时进程所处的工作路径

系统接口的使用 

open|close 

 C语言库函数会调用系统调用接口

open,打开可能会创建

pathname:文件路径

flags:选项

open的返回值:成功了返回文件描述符,失败了返回-1

 清空

 打开一个文件必须包含这三个其中一个,只读,只写,读和写

 如何给函数传递标志位

上面的选项都是宏,对32个比特位进行标记,当作标记位,用整形中不重复的一个bit,就可以标识一种状态

 

 以ONE|TWO 为例 0000 0001 | 0000 0010=0000 0011

0000 0011 & 0000 0001

0000 0011 & 0000 0010

操作系统传标志位的方案就是这样的

我们尝试打开文件

 删除log.txt之后打开失败,当刚才用C语言的方式打开会帮我们创建文件

 这是因为:在应用层看到的一个很简单的动作,在系统接口层面甚至OS层面,可能要做非常多的动作

如果我们想创建文件,就要添加O_CREATE

 

 此时打开成功,文件描述符为3

 但此时权限又有点奇怪

 这就要涉及到open的最后一个参数mode,mode是权限参数

 0代表8进制,权限还是有一些不对666代表rw-rw-rw-

 这是我们的系统里有umask,umask会过滤权限

 umask可以人为设置

 

 此时权限恢复正常

 如果文件已经存在,我们可以使用O_RDONLY

 

 关闭文件 close,传的是文件标志位

 

write 

 向一个fd里写特定的buf,字符个数为conut

 

 

 修改一下再写入

 

 我们发现是从头部开始写入,而不是删除后再写

 这是因为我们加的指令不够

 

 

 追加O_APPEND

 

read

 

 从特定文件描述符,读取数据到buf中,读count个

 read返回值是实际读到的字节数

 文件描述符

 我们发现上面打开文件后,描述符都是3

 

 文件描述符没有0,1,2

这是因为:0,1,2,分别对应stdin,stdout,stderr

证明:

 我们发现往标准输出和往1里面写,照样可以打印在显示器上

 

我们输入123456,仍然可以打印出来 

 

此时仍然可以读取

int类型 0 1 2 和FILE*类型 stdin stdout stderr都可以读取

FILE*的FILE是一个struct结构体,是C标准库提供的,内部有多种成员

C文件库函数内部一定要调用系统调用,在系统角度,系统认的是fd而不是FILE

FILE结构体里面必定封装了fd

stdin/out/err内部绝对有fd

 

fd的理解 

 进程要访问文件,必须先打开文件,一个进程可以打开多个文件,一般而言 进程:打开的文件=1:N,文件要被访问,前提是加载到内存当中

如果多个进程都要打开自己的文件,系统中会存在大量被打开的文件,所以,OS需要把如此多的文件管理起来,管理方式:先描述,再组织

在内核中,OS内部要为管理每一个被打开的文件,构建struct file结构体,打开一个文件就创建struct file的对象或变量,用来充当一个被打开的文件,结构体里面包含了一个被打开的文件的几乎所有的内容(不仅仅包含属性)

如果有很多创建的struct file,会用双链表组织起来

进程和文件的对应关系,用一个数组维护类型是struct file*

 

 fd在内核中,本质是一个数组下标,系统通过数组下标,在数组中做哈希索引,就可以找到对应的打开的文件对象

结论:

当我们使用open打开文件的时候,内核中会创建一个文件对象,然后在数组里找一个没有被使用的格子,把这个格子的地址填到右侧创建的文件对象中,然后把对应的数组下标返回给用户。用户用数组下标就能调用接口,直接根据当前进程的PCB找到数组,然后根据数组索引到文件对象,文件对象中包含了文件的所有内容,找到文件之后,就可以进行操作

猜你喜欢

转载自blog.csdn.net/weixin_49449676/article/details/127446955