深入了解文件IO笔记

深入了解文件IO

1.Linux下文件如何管理

1.1静态文件

文件在没有被打开的情况下一般都是存放在磁盘中的,譬如电脑硬盘、移动硬盘、U 盘等外部存储设
备,文件存放在磁盘文件系统中,并且以一种固定的形式进行存放,我们把他们称为静态文件.
磁盘存储的最小单位: 扇区(sector),每个扇区存储512字节(相当于0.5KB)
块 (block)= 8个扇区 , 4KB

1.2 inode

磁盘进行分区时分为两个区域:数据区和inode区
数据区存放数据例如"hello world"
inode区存放inode table,里面有很多inode节点,每个文件对应一个inode
在这里插入图片描述
在这里插入图片描述

打开一个文件,系统内部会分三步走:

  • 系统找到文件名对应的inode编号
  • 通过inode编号从inode table中找到对应的inode结构体
  • 根据inode结构体中记录的信息,确定文件数据所在 block,并读出数据

1.3 PCB(process control block)进程控制块

定义: Linux系统中,内核为每个进程设置一个专门的数据结构用于管理该进程,譬如用于记录进程的状态信息、运行特征等。
在这里插入图片描述

目的: 为了方便管理进程 ,提升效率
在这里插入图片描述

2.返回错误错误编号errno

2.1 errno变量

在 Linux 系统下对常见的错误做了一个编号,每一个编号都代表着每一种不同的错误类型,当函数执行发生错误的时候,操作系统会将这个错误所对应的编号赋值给 errno 变量,每一个进程(程序)都维护了自己的 errno 变量,它是程序中的全局变量,该变量用于存储就近发生的函数执行错误编号,也就意味着下一次的错误码会覆盖上一次的错误码

本质是int类型的变量,下一次错误码会覆盖上一次的错误码,库文件<errno.h>
在这里插入图片描述

2.2 strerror()函数

库文件:<string.h>
该函数可以将对应的 errno 转换成适合我们查看的字符串信息
在这里插入图片描述

2.3 perror()函数

库文件:<stdio.h>
在这里插入图片描述

3. 空洞文件

在这里插入图片描述

应用场景:在多线程下对文件的写操作
在这里插入图片描述

3.1 再论lseek()函数

空洞文件测试
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

读取文件空洞部分
在这里插入图片描述在这里插入图片描述

4.O_APPEND 和 O_TRUNC 标志

open函数flags参数学习了O_RDONO,O_WRONLY,O_CREAT,O_EXCL等,再学习两个O_APPEND 和 O_TRUNC

4.1 O_TRUNC

如果使用了这个标志,调用 open 函数打开文件的时候会将文件原本的内容全部丢弃,文件大小变为 0;

4.1 O_APPEND

如果 open 函数携带了 O_APPEND 标志,调用 open 函数打开文件,当每次使用 write()函数对文件进行写操作时,都会自动把文件当前位置偏移量移动到文件末尾,从文件末尾开始写入数据,也就是意味着每次写入数据都是从文件末尾开始.

5.同一文件被多次打开

5.1 文件描述符与文件的对应关系

n对1
使用任何一个fd都可对同一文件进行读写操作(文件共享)

5.2 读写位置偏移量是相对的

每个文件描述符都有各自的文件表,所以偏移量是各自维护自己。
在这里插入图片描述

5.3 使用多个文件描述符对同一文件进行写操作

加不加O_APPEND结果是有区别的
在这里插入图片描述 在这里插入图片描述

  • 不加O_APPEND,多个线程操作同一文件时,指针互不干扰,会出现覆盖的问题
  • 加O_APPEND,每次使用write都会使偏移指针指向末尾

6.复制文件描述符

在这里插入图片描述

6.1 dup函数

函数原型
在这里插入图片描述

oldfd:旧文件描述符
返回值:成功 newfd 失败 -1
在这里插入图片描述

6.2 dup2函数

函数原型
在这里插入图片描述

在这里插入图片描述

7.文件共享

7.1 什么是文件共享

同一个文件(譬如磁盘上的同一个文件,对应同一个 inode)被多个独立的读写体同时进行 IO 操作

7.2 常见的文件共享方式

  • 同一进程的多个线程间共享
    ① 同一进程 使用多个open函数打开同一个文件
    在这里插入图片描述

② 同一进程使用dup或dup2函数复制文件
在这里插入图片描述

  • 多个不同的进程间实现共享
    不同进程使用open函数打开同一文件
    在这里插入图片描述

7.3 文件共享存在竞争冒险问题

在这里插入图片描述
在这里插入图片描述

7.4 原子操作

有多步操作组成的一个操作,原子操作要么一步也不执行,一旦执行,必须要执行完所有
步骤,不可能只执行所有步骤中的一个子集。

7.4.1 O_APPEND标志

文件添加flag->O_APPEND后,每次执行write函数,都会自动将偏移指针指向末尾,达到解决竞争冒险问题

7.4.2 pread函数 和 pwrite函数

函数原型
在这里插入图片描述

虽然 pread(或 pwrite)函数相当于 lseek 与 pread(或 pwrite)函数的集合,但还是有下列区别:

  • 调用 pread 函数时,无法中断其定位和读操作(也就是原子操作);
  • 不更新文件表中的当前位置偏移量。
    在这里插入图片描述

使用pread后偏移指针仍是0

7.4.3 O_EXCL标志

场景:两个进程都要创建文件,如果进程A创建文件时被进程B插入,那么文件被B创建,A进而也会创建一个文件,就会出现问题
解决办法就是使用O_CREAT| O_EXCL 防止多个相同文件被创建

8. 截断文件

8.1 truncate 和 ftruncate函数

在这里插入图片描述

在这里插入图片描述

这两个函数的区别在于:ftruncate()使用文件描述符 fd 来指定目标文件,而 truncate()则直接使用文件路径 path 来指定目标文件,其功能一样。

定义:如果文件目前的大小大于参数 length 所指定的大小,则多余的数据将被丢失,类似于多余的部分被“砍”掉了;如果文件目前的大小小于参数 length 所指定的大小,则将其进行扩展,对扩展部分进行读取将得到空字节"\0"。

截断不会改变文件偏移量,需要注意截断后调整偏移量(偏移量和文件大小无关系)

8.2 fcntl 和 ioctl (系统调用)

* fcntl()
> 可以对fd做一系列的控制操作,是一个多功能的文件描述符管理工具
> 例如:复制文件描述符、获取或设置文件描述符、获取状态标志

在这里插入图片描述

可变参函数,fd:文件描述符 cmd:操作命令
⚫ 复制文件描述符(cmd=F_DUPFD 或 cmd=F_DUPFD_CLOEXEC);
⚫ 获取/设置文件描述符标志(cmd=F_GETFD 或 cmd=F_SETFD);
⚫ 获取/设置文件状态标志(cmd=F_GETFL 或 cmd=F_SETFL);
⚫ 获取/设置异步 IO 所有权(cmd=F_GETOWN 或 cmd=F_SETOWN);
⚫ 获取/设置记录锁(cmd=F_GETLK 或 cmd=F_SETLK);
返回值与cmd有关,失败返回-1

示例

  • 复制
    在这里插入图片描述

使用F_DUPFD时需要第三个参数,0表示fd2文件描述符需要大于等于0

  • 得到或修改文件状态标志
    在这里插入图片描述
  • ioctl()
    在这里插入图片描述

    用于操作特殊文件或硬件外设, ioctl是设备驱动程序中对设备的I/O通道进行管理的函数。

偏移量问题

write read 会改变偏移量

多个进程或一个进程多个open同一文件,偏移量互不影响

dup 共用一个偏移量

截断不影响偏移量

lseek调整偏移量

pread pwrite不影响偏移指针

偏移量对于文件大小的影响

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值