0
点赞
收藏
分享

微信扫一扫

文件细节操作简述(LInux应用编程篇)

Mhhao 2022-03-12 阅读 65
目标检测

1、一个进程里多次打开同一个文件

  • 一个进程内多次open打开同一个文件,在内存中并不会存在多份动态文件。
  • 一个进程内多次 open 打开同一个文件,不同文件描述符所对应的读写位置偏移量是相互独立的在这里插入图片描述
    上面因为出现了各自会从头开始写的问题,所以引入O_APPEND标志。就会fd1写完一段,我用fd2写是接着fd2继续写。

2、复制文件符号fd
通过复制文件描述符可以实现接续写。

  • open 返回得到的文件描述符fd 可以进行复制。,复制成功之后可以得到一个新的文件描述符。
  • 在Linux系统下,可以使用dup或 dup2 这两个系统调用对文件描述符进行复制。
  • 因为复制得到的文件描述符与旧的文件描述符指向的是同一个文件表,所以可知,这两个文件描述符的属性是一样(文件的读写权限、文件状态标志、文件偏移量等)
    在这里插入图片描述

3、文件共享

  • 应用场景:多线程或多进程编程环境中:
    1、通过文件共享的方式来实现多个线程同时操作同一个大文件,以减少文件读写时间、提升效率

  • 文件共享的核心是:如何制造出多个不同的fd来指向同一个文件。
    途径:就是 上面的打开同一个文件很多次,复制文件fd。

  • 常见的三种文件共享的实现方式
    1、 同一个进程中多次调用open函数打开同一个文件
    在这里插入图片描述
    因为最后也是指向同一个inode结构体,说明磁盘上的文件位置是一样的

    2、不同进程中分别使用open函数打开同一个文件
    在这里插入图片描述
    因为最后也是指向同一个inode结构体,说明磁盘上的文件位置是一样的

    3、同一个进程中通过复制dup(dup2指定复制后的fd)函数进行fd 的复制
    在这里插入图片描述
    最终都是指向同一个inode结构体,说明文件的物理地址是一样的。

4、竞争冒险

  • 因为linux系统是多task、多进程的操作系统。不管是应用层还是驱动层都会存在竞争冒险。目的很简单就是抢夺CPU的资源。
  • 每个进程都有它自己的进程控制块PCB,有自己的文件表(意味着有自己独立的读写位置偏移量),但是共享同一个 inode节点(也就是对应同一个文件)。
  • 现在举个例子,A、B两个独立的进程,都对同一个文件进行追加写操作。
    在这里插入图片描述
    进程 A 调用 write 函数时,是从进程 A 的该文件当前位置偏移量(1500字节处)开始写入,此时文件 1500字节处已经不再是文件末尾了,如果还从1500字节处写入就会覆盖进程B 刚才写入到该文件中的数据。解决方法就是原子操作

5、原子操作

  • 为了解决竞争冒险的问题,导致两个不同的进程在上下文的切换的工中出现写操作的问题这里提出了原子操作的方法。

  • 其原子操作的核心就是多步操作组成的一个操作,原子操作要么一步也不执行,一旦执行全部执行完

  • 是西安原子操作的方式:
    1、追加O_APPEND标志==实现原子操作
    当 open 函数的 flags 参数中包含了 O_APPEND 标志,每次执行 write 写入操作时都会将文件当前写位置偏移量移动到文件末尾,然后再写入数据。这里移动到文件末尾+写入数据=2步成一步的原子操作

    2、系统调用pread()和pwrite()==实现原子操作
    与read和write的作用一样区别是它具有原子操作。
    一次pread=lseek+read
    一次pwrite=lseek+write
    pread/pwrite不更新文件表中的当前位置偏移量。

6、多功能fd管理大师fcntl

  • fcntl()函数可以对一个已经打开的文件描述符执行一系列控制操作。
    1、复制一个fd(与dup、dup2作用相同)
    2、获取/设置fd标志
    3、获取/设置文件状态标志
/*
头文件:
#include <unistd.h> 
#include <fcntl.h> 
参数:
@	fd:文件描述符。
@	cmd:操作命令,要对 fd 进行什么操作:
	复制文件描述符(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)
@	返回值:
	执行失败情况下,返回-1,并且会设置 errno。
	执行成功的情况下,其返回值与 cmd(操作命令)有关,譬如 cmd=F_DUPFD(复制文件描述符)将返回一个新的文件描述符
*/
int fcntl(int fd, int cmd, ... /* arg */ ) 

7、文件IO操作杂物箱ioctl

  • 可以处理的事情非常杂、不统一,一般用于操作特殊文件
    或硬件外设

/*
@	头文件
	#include <sys/ioctl.h> 
@	fd 文件描述符 此参数与具体要操作的对象有关,没有统一值,表示向文件描述符请求相应的操作
@	request
@	...:此函数是一个可变参函数,第三个参数需要根据 request参数来决定,配合 request来使用
@	返回值:成功返回0,失败返回-1。
*/
int ioctl(int fd, unsigned long request, ...); 

截断文件truncate() 或 ftruncate()

将普通文件截断为指定字节长度

#include <unistd.h> 
#include <sys/types.h> 
 
/*
ftruncate()使用文件描述符 fd来指定目标文件
truncate()则直接使用文件路径path来指定目标文件
*/ 
int truncate(const char *path, off_t length); 
int ftruncate(int fd, off_t length); 
  • 什么是截断?如果文件目前的大小大于参数 length 所指定的大小,则多余的数据将被丢失,类似于多余的部分被“砍”掉了;如果文件目前的大小小于参数 length所指定的大小,则将其进行扩展,对扩展部分进行读取将得到空字节"\0
  • ftruncate之前,必须调用 open()函数打开该文件得到文件描述符,并且必须要具有可写权限,也就是调用 open()打开文件时需要指定O_WRONLY或O_RDWR.
  • 调用这两个函数并不会导致文件读写位置偏移量发生改变,所以截断之后一般需要重新设置文件当前的读写位置偏移量
举报

相关推荐

0 条评论