目录
前言
1. 文件
2. 文件操作
2.1接口介绍
2.2 文件读写
write接口
read接口
使用示例
3. 文件在操作系统中的表现
4. 标准流
5. 虚拟文件系统
6. 总结梳理
文件操作在Linux系统编程中相当重要,也是Linux系统编程的基础,本文将向大家介绍Linux中基础IO接口的使用、文件、标准流、等相关概念,来帮助你快速了解并熟悉文件操作;
在学习基础IO之前,需要一些基础知识的储备,也就是对文件的理解;在日常使用电脑中每天都会用到,文件的种类也有很多比如:图片、视频、文本等;那么文件在操作系统中的存储形式又是怎么的呢?
文件的种类有很多,但在操作系统中,都是这样描述的:文件 = 内容 + 属性;
需要建立以下认识:
- 所有文件的操作:对文件内容操作 和 对文件属性操作
- 文件内容是数据,属性也是数据(存储文件时既要存储文件内容,也要存储文件属性)
- 访问一个文件时,必须要先把文件打开
我们访问文件,本质其实是进程去访问文件,文件在被打开之前,它就是普通文件存储在磁盘当中,想要打开文件,就需要把文件加载到内存当中;
文件可以分为两种:被打开的文件(在内存中) 和 没有被打开的文件(在磁盘中);对文件操作的研究,本质就是进程与被打开文件的关系;
在C语言中的fopen,调用一次打开一个文件,在一个程序中fopen可以调用很多次,也就是说一个进程可以打开多个文件(进程与打开的文件:1:n);所以,被进程打开的文件可能存在多个,将文件加载到内存中这些都是操作系统来做,对于这些打开的文件,操作系统也需要进行管理;如何管理?六字真言:先描述,再组织
一个文件在被打开之前,会先创建一个文件对象(描述被打开的文件),然后通过链表进行管理;
2.1接口介绍
先来回忆一下C语言中的文件操作;
文件打开方式有很多,可使用 man fopen 自行查看
这里解释一下:
- r+以读的方式打开(文件必须存在)
- w以写的方式打开(如果文件存在清空文件,如果不存在会创建文件)
- r+以读写的方式打开(文件必须存在)
- w+以读写的方式打开(文件不存在会新建文件,文件存在时进行写入会清空文件)
- a以追加的方式打开(文件存在则将数据追加到文件末尾,文件不存在则创建新文件)
- a+读写追加的方式打开(文件存在则将数据追加到文件末尾,文件不存在则创建新文件)
这是C语言提供的文件读写操作,操作系统(OS)也提供了文件读写的接口:
可使用 man open 进行查看 ;接口有多个,先了解以下几个即可;
系统原生的接口怎么用?和fopen不太一样;返回值是int类型,并且参数也不一样:
open接口中的 flag 打开文件主要有三种:
- O_RDONLY(只读)
- O_WRONLY(只写)
- O_RDWR(读写)
这三个常量,必须指定一个且只能指定一个;;
- O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
- O_APPEND: 追加写
- O_TRUNC 写的方式打开文件,如果文件不存在就新建文件,如果文件存在 写入时会先清空文件
返回值:
- 成功:新打开的文件描述符 (在下文文件在OS中的表现进行介绍)
- 失败:-1
这些标志符号怎么用?这些符号都是大写的,并且flag参数显示是int类型,由此可以推断,这些标志符都是定义的宏;通过传递不同的标志,来进行不同的操作;
使用示例:
发现 log.txt有点奇怪,出现了高亮,并且它的权限位也很不正常;
这是因为在Linux中创建文件都是有权限的,由于在创建文件时未设置权限导致的权限乱码,可以通过传参的方式设置权限(mode参数);
修改后再次运行:
创建出来的log.txt为什么权限不是666? 这是由于权限掩码导致,我们可以在创建文件接口之前调用umask把权限掩码置为0;
2.2 文件读写
write接口
参数:
- : 文件描述符,指向要读取的文件或设备。
- : 指向存储读取数据的缓冲区。
- : 要读取的最大字节数
返回值:
- 成功时,返回实际写入的字节数(可能小于)。
- 失败时,返回 -1,并设置 errno
使用场景:
向文件或设备写入数据,例如日志文件、网络套接字等;
示例:
read接口
参数:
- : 文件描述符,指向要读取的文件或设备。
- : 指向存储读取数据的缓冲区。
- : 要读取的最大字节数。
返回值:
- 成功时,返回实际读取的字节数(如果返回 0,则表示文件已结束)。
- 失败时,返回 -1,并设置 errno
使用场景:
从文件、设备或网络读取数据,如从文件系统读取文件内容、读取网络请求等;
使用示例
进程与被打开的文件,它们对应的关系如何管理?
在操作系统中,为进程设计一个数据结构: struct file struct(被打开文件的文件描述对象); 这里边有一个非常重要的结构(数组): struct file *fd array[];在进程的 tast strcut (进程控制块PCB)中会有一个指针(files)指向struct file_strcut对象,当一个进程需要打开文件时,操作系统就会把对应的结构体对象地址填到对应的数组位置(3开始);
结构图如下:
调用open接口的时候:
- 创建一个文件结构体对象
- 把文件结构体对象地址填写到struct file_struct的数组中未使用的位置
- 把数组下标返回给上层
这个数组下标也叫文件描述符,这个数据结构也叫进程文件描述符表;
这样设计的好处: 进程和文件双方不会有太多的关联,双方依然是解耦状态
操作系统访问文件,只认文件描述符
上边提到,文件打开时,默认是从进程文件描述符表中数组下标3开始,那0、1、2呢?
一个进程在运行时默认打开三个文件
- 标准输入: stdin(键盘)
- 标准输出:stdout(显示器)
- 标准错误: stderr(显示器)
为什么默认打开?为了让程序员默认进行输入输出代码编写 ! !
它们的类型都是FILE*类型,那FILE是什么?
它本质上其实就是一个结构体,我们在使用fopen时也是FILE* 类型,上述提到:操作系统访问文件,它只认文件描述符,由此可以推断出C语言中的FILE结构体中,它一定封装的有文件描述符;可以验证一下:
在Linux中一切皆文件,硬件设备不同,如何把不同的硬件看待为文件,如何去理解?
在Linux中,虚拟文件系统(VFS)将各种硬件和设备抽象为文件描述对象;文件描述对象中都有对应的读写方法;每个硬件设备文件都有对应的读写方法,这些方法可以通过设备驱动程序来实现;这样也就可以理解为一切皆文件;我们只需调用write和read接口即可对不同硬件进行读写;
这种技术的实现有点像什么?没错,就是我们所学习的多态,虚拟文件系统就是基类,各种硬件设备文件就是派生类,每个设备驱动可以根据需要重写(或实现)相应的方法;
上述的知识,最后来总结梳理一下:
一个进程要打开一个文件,调用 open 接口,首先会为该文件创建一个文件描述对象,然后把文件描述对象地址填写到struct file_struct的数组(文件描述符表)中未使用的位置,把数组下标返回给上层;
要打开文件需要先把文件加载到内存,其中在文件描述对象中包含:文件属性、文件缓冲、方法集(VFS虚拟文件系统);无论是读数据还是写数据,都需要先加载到文件缓冲区;在应用层数据的读写,本质上就是将内核缓冲区的数据进行来回拷贝;
以上便是本文的全部内容,希望对你有所帮助,感谢阅读!
到此这篇怎么建立dbf文件(创建dbf文件)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!
版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/bcyy/78640.html