文件IO_打开和关闭文件(附Linux-5.15.10内核源码分析)

news/2025/3/19 3:00:36/

目录

1.打开文件

1.1 函数原型介绍

1.1.1 open函数

1.1.2 creat函数

1.1.2 openat函数

1.2 内核源码分析

1.3 函数原型区别

2.关闭文件

2.1 函数原型介绍

2.1.1 close函数

2.2 内核源码实现


1.打开文件

1.1 函数原型介绍

1.1.1 open函数

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

函数简介:open函数用于打开一个文件,并返回一个文件描述符,应用程序可以通过文件描述符对文件进行读写等操作。open函数可以打开已经存在的文件,也可以创建一个新文件。

函数参数:

pathname:是文件的路径名。

flags:打开文件时的标志,可以设置为以下值之一或多个值的按位或:

  • O_RDONLY:只读打开
  • O_WRONLY:只写打开
  • O_RDWR:读写打开
  • O_CREAT:如果文件不存在,则创建文件
  • O_TRUNC:如果文件存在且以写方式打开,则截断文件为零长度
  • O_APPEND:以追加方式打开文件

mode:只有在O_CREAT标志被设置时才有效,用于指定文件的访问权限,可以设置为以下值之一:

#define S_IRWXU 00700 //用户可读,可写,可执行
#define S_IRUSR 00400 //用户可读
#define S_IWUSR 00200 //用户可写
#define S_IXUSR 00100 //用户可执行#define S_IRWXG 00070 //组可读,可写,可执行
#define S_IRGRP 00040 //组可读
#define S_IWGRP 00020 //组可写
#define S_IXGRP 00010 //组可执行#define S_IRWXO 00007 //其他用户可读,可写,可执行
#define S_IROTH 00004 //其他用户可读
#define S_IWOTH 00002 //其他用户可写
#define S_IXOTH 00001 //其他用户可执行

mode可以通过八进制赋值,例如设置为0777,0777表示所有权限按位或。

需要注意的是mode需要与系统umask值共同作用才能得到最终的文件权限,umask作用去掉哪些权限,比如umask值为0022(八进制),标识去掉S_IWGRP和S_IWOTH权限。

文件最终权限计算方法为: mode &~ umask.

举例说明:

mode设置为0777,umask值为0022,文件最终权限为0755。

函数返回值:

成功:返回文件描述符,文件描述符为非负整数。

失败:返回-1,并设置errno。

示例代码

#define TEST_FILE "/tmp/test.txt"int open_test() {int fd = open(TEST_FILE, O_RDWR | O_CREAT | O_TRUNC, 0777);if (fd == -1) {perror("open error");return -1;}return 0;
}

1.1.2 creat函数

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int creat(const char *pathname, mode_t mode);

函数简介:creat函数用于创建并打开一个新文件,并返回一个文件描述符,如果文件已经存在,则会将其截断为0字节,应用程序可以通过文件描述符对文件进行读写等操作。

函数参数:

pathname:文件路径名。

mode:是新文件的权限(参考open函数)。

函数返回值:

成功:返回文件描述符,文件描述符为非负整数。

失败:返回-1,并设置errno。

示例代码:

int creat_test() {int fd = creat(TEST_FILE, 0644);if (fd == -1) {perror("creat error");return -1;}return 0;
}

1.1.2 openat函数

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int openat(int dirfd, const char *pathname, int flags);
int openat(int dirfd, const char *pathname, int flags, mode_t mode);

函数简介:openat函数用于在指定目录下打开文件并返回文件描述符。它与open函数类似,但可以指定相对路径来打开文件,而不需要提供完整的文件路径。

函数参数:

dirfd:已打开的文件目录描述符。

pathname:是指定文件名的字符串。

flags:打开文件时的标志(参考open函数)。

mode:是新文件的权限(参考open函数)。

openat函数dirfd和pathname参数组合关系:

  • 组合1:pathname为绝对路径时,按绝对路径方式打开文件,dirfd失效。
  • 组合2:pathname为相对路径时,由dirfd(文件目录)和pathname(相对路径)共同决定打开的文件名。
  • 组合3:pathname为相对路径时,如果dirfd设置为AT_FDCWD(当前工作目录),由dirfd(当前工作目录)和pathname(相对路径)共同决定打开的文件名。

函数返回值:

成功:返回文件描述符,文件描述符为非负整数。

失败:返回-1,并设置errno。

示例代码:

#define DIR_PATH "/tmp"
#define FILE "test.txt"
int openat_test() {int dirfd = open(DIR_PATH, O_RDONLY);if (dirfd == -1) {perror("open dir error");return -1;}int fd = openat(dirfd, FILE, O_RDWR | O_CREAT | O_TRUNC, 0644);if (fd == -1) {perror("openat error");return -1;}return 0;
}

1.2 内核源码分析

图 1-1 open函数内核源码分析

open,creat,openat通过系统调用再调用一个共同的函数do_sys_open函数,do_sys_open函数有四个参数:dfd,path,flags,mode。这四个参数对应openat函数原型四个参数。

open函数没有dfd参数,所以在调用do_sys_open函数之前dfd设置为默认值AT_FDCWD(当前工作目录)。

creat函数没有dfd参数和flags参数,所以在调用do_sys_open函数之前dfd设置为默认值AT_FDCWD(当前工作目录),以及flags设置为默认值O_WRONLY | O_CREAT | O_TRUNC,creat因为flags默认值的关系,所以只能新建文件或者截断文件长度至0来打开文件。

openat函数需要传递四个参数至do_sys_open函数。

打开文件描述符系列函数源码调用路径如图,这里就不再赘述。

1.3 函数原型区别

 (1)open函数和creat函数区别

  • 区别1:open函数可以打开已存在的文件,也可以创建新文件,而creat函数只能创建新文件。如果文件已存在,creat函数会将其截断为零长度。
  • 区别2:open函数的标志参数可以更加灵活地指定文件的打开方式,包括只读、只写、读写、追加等选项。而creat函数只能以写方式打开文件,并且具有固定的标志(O_WRONLY | O_CREAT | O_TRUNC)。

(2)open函数和openat函数区别

  • 区别1:open函数接受一个文件路径名作为参数,该路径名可以是绝对路径或相对路径。 openat函数需要传递一个已打开的目录文件描述符(dirfd)和一个相对于该目录的路径名作为参数。这种方式可以更加灵活地控制文件的打开位置。
  • 区别2:目录解析方式: open函数的文件路径名会根据当前进程的工作目录进行解析。 openat函数的路径名是相对于提供的目录文件描述符(dirfd)进行解析。
  • 区别3:安全性考虑: open函数在解析文件路径时,依赖于进程的当前工作目录。这可能会导致安全性问题,特别是在多线程环境下,因为当前工作目录是共享的。 openat函数提供了更安全的方式,可以避免依赖于进程的当前工作目录,而是通过提供目录文件描述符来指定相对路径。

2.关闭文件

2.1 函数原型介绍

2.1.1 close函数

#include <unistd.h>int close(int fd);

函数简介:close函数的作用是关闭文件描述符并释放相关资源。

函数参数:

fd:表示需要关闭的文件描述符。

函数返回值:

成功:返回0.

失败:返回-1,并设置errno,一些常见的错误码包括:

  • EBADF:无效的文件描述符,即文件描述符未打开或已经关闭。
  • EINTR:操作被信号中断。
  • EIO:I/O错误。

2.2 内核源码实现

图 2-1 close函数内核源码分析

 close函数通过系统调用sys_close函数进入内核空间,close通过fd找到struct file对象并清除和释放该对象,struct file的f_op成员会根据文件系统和文件类型不一样而设置不同的值,关闭文件时,也会调用f_op对应的一些具体函数清除资源,典型的情况如socket关闭,socket关闭需要完成三次握手,需要通过f_op->release函数实现。


http://www.ppmy.cn/news/846652.html

相关文章

天龙八部架设IP配置文件

我来揭秘一下天龙八部架设IP配置 得到的端解压出来找到ServerInfo.ini文件&#xff0c;这个就是用来通讯配置Ip文件了 [System] Desc0功能&#xff1a;配置服务器端程序的相关情况&#xff1b; Desc1IP0、Port0指外网的地址和端口&#xff1b; Desc2IP1、Port1指内网的地…

天龙八部之---看虚竹一生

虚竹同学恐怕是金庸学堂里英雄班中最让人不服气的一个。 论相貌&#xff0c;“浓眉大眼&#xff0c;一个大大的鼻子扁平下塌&#xff0c;容貌颇为丑陋”&#xff0c;做人迂腐呆板&#xff0c;口齿笨拙&#xff0c;琴棋书画不精&#xff08;也就围棋懂点皮毛&#xff09;&#x…

天龙八部服务端数据传递

不管玩什么游戏都有个服务端与客户端&#xff0c;就是传递数据。来看看天龙八部的数据传递是怎么样的 把端解压出来找到这个文件Script.dat 看文件 MGR_TXT ;洛阳NPC 000000\obj\luoyang\oluoyang_suzhe.lua 000001\obj\luoyang\oluoyang_caijing.lua 000002\obj\lu…

天龙八部怀旧服务器维护,新天龙八部玩家苦寻当年的师傅,8年间玩了十个服务器...

对我来说&#xff0c;玩天龙八部端游是一段非常特殊的经历&#xff0c;它是我青春时代里爱上的第一款游戏&#xff0c;也承载了我很多很多简单而又美好的回忆。 趁着新天龙八部怀旧服10.16不删档开启之际&#xff0c;我想和大家分享一下这些年里我的游戏历程&#xff0c;送给曾…

[python]《天龙八部》文本处理

1、读取每章标题 2、统计人物出现的次数 3、将1和2输出为txt和excel # 处理小说文本 # ———————————————————————————————————————————————————————————————————————————————————————…

天龙八部源码描述

天龙八部(武侠世界)的源码很可能是天龙八部代码流出后改写的&#xff0c;因为在看了代码中可以找到一些证据&#xff0c;整个客户端分为&#xff1a;一个是编辑器&#xff0c;一个是客户端&#xff0c;采用OGREcegui自写的简单的物理碰撞检测FMOD自写的网络库。 服务器端代码目…

天龙八部服务器端Lua脚本系统

一、Lua脚本功能接口 1. LuaInterface.h/.cpp声明和实现LuaInterface。 LuaInterface成员如下&#xff1a; //脚本引擎 FoxLuaScript mLua ; //注册器 LuaCFuncRegister mFuncRegister; //场景关联 Scene* mOwner; //已经读取的脚本表 IDTable m_ScriptTable ; 主要方…

天龙八部中的扫地僧的真实身份

天龙八部中的扫地僧被很多人认为是金庸小说中的第一高手。       1、扫地僧出场时&#xff0c;“一个身穿青袍的枯瘦僧人拿着一把扫帚&#xff0c;正在弓身扫地。这僧人年纪不少&#xff0c;稀稀疏疏的几根长须已然全白”&#xff0c;又说他来了“不知是四十二年&#xf…