Linux笔记 --- IO编程之文件操作

目录

文件操作

系统IO

打开、关闭

读写

调整读写位置

复制文件描述符


文件操作

对一个文件来说有两种不同的操作方式,既可以使用由操作系统提供的编程接口(API),即系统调用,也可以使用标准C库提供的标准IO函数

在几百个Linux 系统调用中,有一组函数是专门针对文件操作的,比如打开文件、关闭文件、读写文件等,这些系统调用接口就被称为"系统IO",相应地,在几千个标准C库函数中,有一组函数也是专门针对文件操作的,被称为"标准IO",他们是工作在不同层次,但都是为应用程序服务的函数接口。

下面我们来逐一对系统IO函数和标准IO函数中最重要最常用的接口进行详细剖析,理解他们的异同,以便于在程序中恰当地使用他们。

系统IO

我们首先使用几个简单的函数进行举例

打开、关闭

此表确实一个flags参数,O_CREAT,创建文件,如果使用了这个参数则要指定mode的值

使用系统调用open()需要注意的问题有:

1,flags的各种取值可以用位或的方式叠加起来,比如创建文件的时候需要满足这样的选项:读写方式打开,不存在要新建,如果存在了则清空他。那么此时指定的flags的取值应该是:O_RDWR|O_CREAT|O_TRUNC

2,mode是八进制权限,比如0644,或者0755等,具体值有表参考。

3,它可以用来打开普通文件、块设备文件、字符设备文件、链接文件和管道文件,但只能用来创建普通文件,每一种特殊文件的创建都有其特定的其他函数。

4,其返回值就是一个代表这个文件的描述符,是一个非负整数。这个整数将作为以后任何系统IO函数对其操作的句柄,或称入口。

close函数只需要提供一个文件描述即可使用关闭biaozhun件

cpp 复制代码
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>

int main(int argc, char const *argv[])
{
    int fd = open("open.txt",O_CREAT|O_TRUNC|O_WRONLY,0644);
    printf("%d\n",fd);

    close(fd);
    return 0;
}

此处结果打印为3,代表第四个文件,012分别代表标准输入、标准输出、标准出错,通常用STDIN_FILNO、STDOUT_FILENO、STDERR_FILENO进行代替

那么,这个所谓的文件描述符究竟是什么玩意儿呢?其实他是一个数组的下标值,在内核中打开的文件是用 file 结构体来表示的,每一个结构体都会有一个指针来指向他们,这些指针被统一存放在一个叫做 fd_array 的数组当中,而这个数组被存放在一个叫做 files_struct 的结构体中,该结构体是进程控制块 task_struct 的重要组成部分。他们的关系如图所示。

上图中task_struct 被称为进程控制块(Process Control Block),是程序运行时在 内核中的实现形式。它里面包含了一个进程在运行时的所有信息,当然就包括了进程在运行过程中所打开文件的信息,这些信息被一个files指针加以统一的管理,files 指针所指向的结构体files_struct{}里面的数组fd_array[]是一个指针数组, 用户空间每一次调用open()都会使得内核实例化一个file{}结构体并将一个指向该结构体的指针依次存放在fd_array[]中,并且该指针所占据的数组下标将作为所谓的"文件描述符(file descriptor)"返回给用户空间的调用者,这就是为什么文件描述符是非负整数的原因。

读写

这两个函数都非常容易理解,需要特别注意的是:

1,实际的读写字节数要通过返回值来判断,参数count只是一个"愿望值"。

2,当实际的读写字节数小于count时,有以下几种情形:

A)读操作时,文件剩余可读字节数不足count

B)读写操作期间,进程收到异步信号。

3,读写操作同时对f_pos起作用。也就是说,不管是读还是写,文件的位置偏移量(即内核中的f_pos)都会加上实际读写的字节数,不断地往后偏移。因此连续的对同一个目标文件进行写操作和读操作会无法读取数据

调整读写位置

针对上面的第三点问题,我们可以使用下面这个函数对普通文件的读写位置进行手动调整

从效果来看,我们不仅可以通过lseek()来调整当前文件偏移量,甚至还可以可以将位置偏移量调整到文件之外,形成一个空洞,这种特性其实是非常重要的,它提供了可以在不同地方同时写一个文件的可能,对于一个较大的文件而言,我们可以通过在文件中定位到一个指定的地方,让多个进程同时在不同的偏移量处写入文件数据。

复制文件描述符

对于dup来说复制的目标作为返回值返回,dup2则可以通过newfd指定复制后的存放描述符,如果这个指定的描述符已经存在则覆盖

复制原有的文件描述符相当于对文件描述符进行一次重定向

多功能函数

ioctl函数中存放了大量的除了读和写以外的功能,但是因为没有统一规范因此被称为"垃圾桶", 而fcntl函数则是对其进行规范化后的函数,因此不到万不得已不要轻易使用ioctl函数

这两个都是变参函数,先来看下 ioctl(),其 request是一个由底层驱动提供的命令字,一些通用的命令字被放置在**头文件/usr/include/asm-generi/ioctls.h(不同的系统存放 位置也许不同)**中,后面的变参也由前面的request命令字决定。比如调整文件为异步工作模式:

cpp 复制代码
int on =1;

ioctl(fd, FIOASYNC, &on);

上述代码将fd对应的文件的工作模式设置为所谓的异步方式,FIOASUNC就是其中的一个通用的命令字,而后续的变量on则是其所需要的对应的值。这个操作也可以用fcntl()来达到:

cpp 复制代码
fcntl(fd, F_SETFL, O_ASYNC);

对于fcntl()而言,其第二个参数命令字cmd有很多,具体查看手册及教程,《LINUX环境编程图文指南》P357

内存映射

该函数在进程的虚拟内存空间中映射出一块内存区域,用于对应指定的一个文件,该内存上的数据跟指定文件的数据一一对应,并在一开始使用文件的内容对这块内存进行初始化

相关推荐
云边有个稻草人6 分钟前
AIGC与虚拟身份及元宇宙的未来:虚拟人物创作与智能交互
笔记·算法·aigc
simple_ssn1 小时前
汇编学习笔记
汇编·笔记·学习
呆呆洁ᵔ·͈༝·͈ᵔ2 小时前
Scala迭代更新
笔记·scala
网络安全(华哥)2 小时前
linux 网络安全不完全笔记
linux·笔记·web安全
纪伊路上盛名在2 小时前
NCR+可变电荷块——文献hub1
笔记·学习·知识图谱·学习方法
Hacker_xingchen6 小时前
网络安全笔记
网络·笔记·web安全
lulinhao11 小时前
IP组播基础
笔记·计算机网络·华为
代码欢乐豆11 小时前
计算机网络——期末复习(3)4-6章考试重点
笔记·计算机网络
红色的山茶花11 小时前
YOLOv9-0.1部分代码阅读笔记-loss_tal_dual.py
笔记·深度学习·yolo
一棵开花的树,枝芽无限靠近你12 小时前
【PPTist】表格功能
前端·笔记·学习·编辑器·ppt·pptist