linux函数深入探索——open函数打开文件是否将文件内容加载到内存空间

摘要:
接下来是我的探索过程和代码的第一步:我使用open函数打开一个文件,并将连续读取间隔设置为3秒。

转自:https://blog.csdn.net/qq_17019203/article/details/85051627

问题:open(2)函数打开文件是否将文件内容加载到内存空间

首先,文件打开后都会产生一个文件描述符fd,这个文件描述符其实是记录在PCB的文件描述符表中,而这个文件描述符实质上是一个结构体,用来存放跟打开文件相关的信息,基于此前提,我产生了两种假设

1、文件描述符结构体中只存储了文件在硬盘中的相应地址信息,并不将文件内容加载到内存中,这样做的好处是减少内存空间的占用,但大大增加了运行的时间(cpu存取内存数据的速度约ns级别,cpu存取硬盘数据的速度约为60000ns)。

2、文件描述符结构体为文件在内存中分配了地址空间来存放文件内容,这样做的好处是增加了运行速度,不足是当文件太大时严重占用内存空间。

3、如果问题2正确就产生了另一个问题,这块地址空间的大小和分配规则是什么?

接下来是我的探索过程和代码

第一步:我用open(2)函数打开了一个文件,设置连续读取文件,读取的间隔为3秒。

第二步:在读取的过程中我将还没被读取完的文件删除(另外打开一个bash,用rm命令删除)

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc,char *argv[])
{
int fd;
char buf[128];
int read_size,write_size;
//open a file with read and write
fd = open(argv[1],O_RDWR);
if(fd == -1)
{
perror("open");
return 1;
}
while(1)
{
read_size = read(fd,buf,2);
if(read_size == 0) break;
write(1,buf,read_size);
sleep(3);
}
//close fd
close(fd);
return 0;
}
下面是运行结果:

bash 1

[sun@localhost file_func]$ ./a.out hello
#include <stdio.h>
#include <unistd.h>

int main(int argc,char *argv[])
{
int link_flag;
link_flag = link(argv[1],argv[2]);
if(link_flag == -1)
{
perror("link");
return 1;
}
if(link_flag == 0)
printf("creat hard link success... ");

return 0;
}
bash 2

[sun@localhost file_func]$ rm hello
通过以上的结果我们能看出,在文件还没被读取完时将文件删除不会影响读取程序继续读取文件内容

结论1:用open(2)函数打开文件会将文件的内容加载到内存空间

接下来我们要探索的是,这个分配的地址空间大小上限是多少,文件类型的不同会不会产生不同的结果等问题

补充:

以上实验还存在一种可能性,就是rm 的原理和unlink是一样的(即rm是通过unlink封装的),等待程序运行完才会删除文件(阻塞删除),虽然删除文件操作是在文件执行完以后,但只要执行unlink文件马上就会消失看不到(在系统界面上消失,但在硬盘上还存在)

为了探索rm是不是通过unlink封装,我又进行了以下操作

一、创建虚拟映像使用rm命令

二、通过strace命令获取rm运行时产生的系统调用,命令如下

strace -f -F -o ./log.txt a.out
 三、在系统调用里查找是否存在unlink函数

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(void)
{
pid_t pid;
//creat child process
pid = fork();
if(pid == -1)
{
perror("fork");
return 1;
}
//child process
if(pid == 0)
{
//load a memory
int ex_flag=execlp("/bin/rm","rm","hello",NULL);
if(ex_flag == -1)
{
perror("execlp");
return 2;
}
return 0;
}
//father process
else
{
wait(NULL);
}

return 0;
}
 通过strace产生的结果如下

mmap(0x3f02d8e000, 18600, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x3f02d8e000
13697 close(3) = 0
13697 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0665bb5000
13697 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0665bb4000
13697 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0665bb3000
13697 arch_prctl(ARCH_SET_FS, 0x7f0665bb4700) = 0
13697 mprotect(0x3f02d89000, 16384, PROT_READ) = 0
13697 mprotect(0x3f0241f000, 4096, PROT_READ) = 0
13697 munmap(0x7f0665bb6000, 51177) = 0
13697 brk(0) = 0x187b000
13697 brk(0x189c000) = 0x189c000
13697 open("/usr/lib/locale/locale-archive", O_RDONLY) = 3
13697 fstat(3, {st_mode=S_IFREG|0644, st_size=99158576, ...}) = 0
13697 mmap(NULL, 99158576, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f065fd22000
13697 close(3) = 0
13697 ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
13697 newfstatat(AT_FDCWD, "hello", {st_mode=S_IFREG|0666, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
13697 geteuid() = 500
13697 newfstatat(AT_FDCWD, "hello", {st_mode=S_IFREG|0666, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
13697 faccessat(AT_FDCWD, "hello", W_OK) = 0
13697 unlinkat(AT_FDCWD, "hello", 0) = 0
13697 close(0) = 0
13697 close(1) = 0
13697 close(2) = 0
13697 exit_group(0) = ?
13696 <... wait4 resumed> NULL, 0, NULL) = 13697
13696 --- SIGCHLD (Child exited) @ 0 (0) ---
13696 exit_group(0) = ?
我们可以看到倒数第8行出现了一个unlinkat系统调用函数,根据unlinkat函数的定义,第三个参数取0时,unlinkat等价于unlink。

通过以上分析,我有以下结论:

1、open(2)函数在打开文件时,是否将文件内容加载到内存空间目前无法得知,在学习的时候老师的理论是linux在读取文件时候会将文件的地址内容加载到内存,而非文件的内容。

2、第一个实验结果主观上来看,因为在删除掉被读取文件后文件还能继续读取,所以open函数打开文件是将文件内容加载到内存空间的。

     但通过客观分析,我们发现我们所认为的“rm删除文件,文件不在系统界面显示就是被删除了”这种想法是不对的,因为rm删除文件是调用了unlinkat系统函数,所以虽然在文件被读取时候我们看不到被读取文件在系统中显示,但此时文件还是存在于硬盘中的,只有当被读取文件被读取完成后才会真正的被删除。
————————————————
版权声明:本文为CSDN博主「虚渊玄」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_17019203/article/details/85051627

免责声明:文章转载自《linux函数深入探索——open函数打开文件是否将文件内容加载到内存空间》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇WPF简介echarts markLine 辅助线非直线设置下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

等了整整12年!Linux QQ 终于更新了!

来自:快科技 作者:上方文Q链接:http://news.mydrivers.com/1/681/681039.htm 2019年10月24日,也就是“1024程序员节”的时候,腾讯突然发布了Linux系统版本的QQ,官方也宣称“全新回归”。 这是因为在2008年的时候,腾讯曾经发布过一次Linux QQ,但如同浪花一般随即消失得无影无踪,如今随着Linu...

linux下jdk,tomcat的安装

一、安装jdk 1、jdk下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html 注: 32位安装包为:jdk-7u17-linux-i586.tar.gz 64位安装包为:jdk-7u17-linux-x64.tar.gz 2、jd...

linux dialog详解(图形化shell)

  liunx 下的dialog 工具是一个可以和shell脚本配合使用的文本界面下的创建对话框的工具。每个对话框提供的输出有两种形式:   1.  将所有输出到stderr 输出,不显示到屏幕。   2.  使用退出状态码,“OK”为0,“NO”为1,"ESC"为255   通用选项 common options:(这个选项来设置dialog box的背...

Matlab安装:Windows&amp;amp;Linux

Matlab 环境配置 Windows Windows下,使用软件管家参照安装即可(这个破解过程实际上添加了两个文件,一个是密钥文件,license.lic 文件,另一个是net配置文件,应该是提供“虚假校验”用的) 当然,学校也购买了正版,直接使用正版授权码激活也可,这个的好处是也可以及时获得更新之类的。 Linux 资源MATLAB Linux...

ESP32开发(2)esp32-cam采集图像

ESP32-CAM摄像头开发板 USB转串口下载器 杜邦连接线若干        注意:GPIO0连接GND(下拉)的作用是让ESP32-CAM进入下载启动模式,这个模式里,才能利用Arduino IDE给ESP32编程,否则IDE会报错,代码烧录完成后,我们需要断开GPIO0和GND的连接,让ESP32进入正常的内存启动模式。 配置ESP32环...

【Docker】选择存储驱动

参考教程:https://docs.docker.com/storage/storagedriver/select-storage-driver/以下内容来自官方文档翻译 环境 virtual box 6.1 centos 7.8 docker 19.03 Docker 的存储驱动 Ideally, very little data is writte...