【Linux系统化学习】文件描述符fd

2024-02-07 01:52

本文主要是介绍【Linux系统化学习】文件描述符fd,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

基础IO预备知识

C语言文件接口

"w"的方式打开,fputs写入

以"a"的方式打开,fputs写入

使用位图传参

系统调用操作文件

open的使用

 第一种形式

第二种形式

write()

文件描述符

文件描述符和进程的关系

默认的三个IO流和文件描述符的关系


基础IO预备知识

在之前的文章中我们提到过:文件 = 内容 + 属性

我们直接给出下面几条结论:

  • 对所有的文件的操作:a.对内容操作 b.对属性操作
  • 内容是数据,属性其实也是数据;因此储存文件必须储存内容和属性。
  • 我们想要访问一个文件,就必须先将这个文件打开。
  • 通过进程打开文件且一个进程可以打开多个文件。
  • 未被打开的文件存储在磁盘中,打开的文件存储在内存中。

我们知道文件默认是在磁盘中的,我们想要打开文件就必须访问磁盘;用户是没有权限访问磁盘的必须使用系统调用,通过操作系统将文件从磁盘加载到内存中进行操作。使用系统调用就要创建进程,因此用户是通过进程打开文件的,一个进程又可以打开很多个文件;打开的文件像内存中的进程一样,进程需要被管理,打开加载在内存中的文件也需要被管理。操作系统管理的方式——先描述在组织;像进程一样,一个文件被打开一定要现在内核中形成被打开的文件对象,然后再将这些文件对象使用某种数据结构串联起来即可。

在本篇文章中我们研究文件操作的本质是:进程和文件的关系


C语言文件接口

在之前C语言的文件操作中我们学习了一些相关C语言的文件操作包括以各种方式打开文件,关闭文件等等。这里我们只简单复习下以”w”和“a"的方式打开文件及使用fputs向文件中写入。

"w"的方式打开,fputs写入

  1 #include<stdio.h>2 int main()3 {4     FILE* fp = fopen("log.txt","w");5     if(fp)6     {7         perror("fopen");8     }9     fputs("aaaaaaaaaaaaaaaaaa",fp);                                                     10     fclose(fp);               11     return 0;                 12 }  

 

总结:以读("w")的方式打开文件,当文件不存在时候会在当前工作目录下创建新文件;但是以这个方式写入是从头开始覆盖式写入,相当于将之前文件的内容清空再写入。相当于Linux中的输入重定向。

以"a"的方式打开,fputs写入

  1 #include<stdio.h>2 int main()3 {4     FILE* fp = fopen("log.txt","a");5     if(fp)6     {7         perror("fopen");8     }9     fputs("ccccccccccccc",fp);                                                          12     fclose(fp);13     return 0;14 }

总结:以追加("a")的方式打开文件,会在文件末尾进行写入。相当于Linux下的追加重定符。

 


使用位图传参

在学习Linux的系统调用之前我们还要学习下使用位图传参。

对于我们的自定义函数来说,定义了几个参数在使用时候就要传几个实参;但是我们传递的实参非常多时,又对应函数参数的一个参数该怎么办?

将我们的参数按位与(|)形成一个新的参数,这个参数的每个比特位为代表一个参数; 对传入的参数进行位操作即可。

  1 #include <stdio.h>2 3 #define Print1 1      // 00014 #define Print2 (1<<1) // 00105 #define Print3 (1<<2) // 01006 #define Print4 (1<<3) // 10007 8 void Print(int flags)9 {10     if(flags&Print1) printf("hello 1\n");11     if(flags&Print2) printf("hello 2\n");12     if(flags&Print3) printf("hello 3\n");13     if(flags&Print4) printf("hello 4\n");14 }15 16 17 int main()18 {19     Print(Print1);20     Print(Print1|Print2);21     Print(Print1|Print2|Print3);22     Print(Print3|Print4);23     Print(Print4);24     return 0;25 } 

 

如上面的代码那样使用位图的思想解决多个实参对应一个实参进行传参操作。 


系统调用操作文件

上面我们提到操作系统是不相信我们用户的,用户直接对操作系统的文件操作不了;需要使用操作系统提供的系统接口——open、close。open系统调用代表打开文件,close代表关闭文件。

open的使用

open系统调用含有两种形式,第一种形式适用于打开存在的文件,当打开不存在时会造成文件的权限乱码;第二种形式适用于打开不存在的文件。此函数的返回值大于0代表打开成功打开文件,小于0代表打开失败。

参数说明

pathname:打开的文件名

flags:对文件进行各种操作对应数字的按位与(|),下面的几个参数为常用的操作对应数字的宏定义。

        O_WRONLY:只读

        O_CREAT:创建新文件

        O_TRUNC:覆盖式写入

        O_APPEND:追加式写入

mode:形成新文件的权限

 第一种形式

  1 #include<stdio.h>2 #include<sys/types.h>3 #include<sys/stat.h>4 #include<fcntl.h>5 #include<unistd.h>                                                                      6 7 int main()8 {9     int fb = open("vlog.txt",O_WRONLY|O_CREAT|O_TRUNC);10     if(fb<0)11     {12         perror("open");13         return 0;14     }15     close(fb);16 }

如上图所示:权限只有rwx,这里蹦出来一个T,显然乱码了。 

第二种形式

1 #include<stdio.h>2 #include<sys/types.h>3 #include<sys/stat.h>4 #include<fcntl.h>5 #include<unistd.h>6 7 int main()8 {9     int fb = open("vlog.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);                            10     if(fb<0)11     {12         perror("open");13         return 0;14     }15     close(fb);16 }

总结:通过第二种函数我们将创建的新文件的权限进行设置,但是系统中含有umask。设置的权限和文件的权限不一样,需要我们手动修改umask之后便可以相同。

write()

这个系统调用是用来对文件进行写入操作的;返回值我们会在以后的文章中介绍此处不用过多了解。

参数说明

  • fb:需要进行操作的文件描述符
  • buf:需要写入的字符串(这个字符串不用以’\0‘结尾,因为这个规定是C语言的不是文件系统的
  • count:写入字符串的长度的

写入的方式和打开时传入的参数有关。


文件描述符

使用系统调用open会返回一个整形,这个整形叫做文件描述符。并且使用系统调用write以这个整形为参数时会对文件写入,感觉好神秘,通过一个整数对系统文件操作。

一个进程可以打开多个文件,我们不妨打开好几个文件将每个文件的文件描述符打印出来。

 #include<stdio.h>2 #include<sys/types.h>3 #include<sys/stat.h>4 #include<fcntl.h>5 #include<unistd.h>6 #include<string.h>7 int main()8 {9     int fba = open("fba.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);10     int fbb = open("fbb.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);11     int fbc = open("fbc.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);12     int fbd = open("fbd.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);13     printf("%d\n",fba);14     printf("%d\n",fbb);15     printf("%d\n",fbc);16     printf("%d\n",fbd);                                                                 17     return 0;}

是从3开始的连续小整数,其实这三个整数是数组的下标

文件描述符和进程的关系

上面我们提到一个进程可以打开很多文件,操作系统为了方便管理这些文件会对每个文件编写相应的结构体即 struct file,但是操作系统不想让进程和每个文件对应的结构体耦合过大,因此对此进程打开的所有文件又组织起来创建一个结构体 struct files _struct,在此进程的PCB中含有一个 struct files_struct * files指向这个结构体;其中这个结构体中还有一个指针数组,从下标3开始数组中的每个元素为struct file * fd ,一一指向这个进程打开的文件。

结论:操作系统访问文件只认文件描述符。

默认的三个IO流和文件描述符的关系

刚开始学习Linux的时候就说过一个特别重要的结论:Linux下一切皆文件;当我们使用键盘、显示器编写C语言(包含其他编程语言)的时候,其实就是对键盘文件、显示器文件进行文件读写;当我们执行C语言的时候系统默认给我们打开三个流:stdin、stdout、stderr。这三个流分别对应我们的键盘、显示器、显示器;用于我们进行输入、输出,像scanf就是对键盘文件的读取、printf就是对显示器的写入。(stderr流会在后面的文章中介绍到)

这三个流对应的返回值是FILE*,和C语言对系统文件的各种函数的返回值一样。C语言可以对系统中的文件进行操作,必定封装了系统调用open、close。FILE用来保存打开文件的信息的,里面肯定封装了文件描述符(fd);因此我们可以使用C语言对系统文件进行操作。

  1 #include<stdio.h>2 #include<sys/types.h>3 #include<sys/stat.h>4 #include<fcntl.h>5 #include<unistd.h>6 #include<string.h>7 int main()8 {9     printf("stdin->fd:%d\n ",stdin->_fileno );10     printf("stdout->fd:%d\n ",stdout->_fileno );11     printf("stderr->fd:%d\n ",stderr->_fileno );12     13     FILE* fp =fopen("vlog.txt","w");14     printf("fp->fd:%d \n",fp->_fileno);15     fclose(fp);                                                                         16           }


今天对Linux下文件描述符的分享到这就结束了,希望大家读完后有很大的收获,也可以在评论区点评文章中的内容和分享自己的看法;个人主页还有很多精彩的内容。您三连的支持就是我前进的动力,感谢大家的支持!!! 

这篇关于【Linux系统化学习】文件描述符fd的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/686192

相关文章

防止Linux rm命令误操作的多场景防护方案与实践

《防止Linuxrm命令误操作的多场景防护方案与实践》在Linux系统中,rm命令是删除文件和目录的高效工具,但一旦误操作,如执行rm-rf/或rm-rf/*,极易导致系统数据灾难,本文针对不同场景... 目录引言理解 rm 命令及误操作风险rm 命令基础常见误操作案例防护方案使用 rm编程 别名及安全删除

Linux下MySQL数据库定时备份脚本与Crontab配置教学

《Linux下MySQL数据库定时备份脚本与Crontab配置教学》在生产环境中,数据库是核心资产之一,定期备份数据库可以有效防止意外数据丢失,本文将分享一份MySQL定时备份脚本,并讲解如何通过cr... 目录备份脚本详解脚本功能说明授权与可执行权限使用 Crontab 定时执行编辑 Crontab添加定

使用docker搭建嵌入式Linux开发环境

《使用docker搭建嵌入式Linux开发环境》本文主要介绍了使用docker搭建嵌入式Linux开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1、前言2、安装docker3、编写容器管理脚本4、创建容器1、前言在日常开发全志、rk等不同

linux系统上安装JDK8全过程

《linux系统上安装JDK8全过程》文章介绍安装JDK的必要性及Linux下JDK8的安装步骤,包括卸载旧版本、下载解压、配置环境变量等,强调开发需JDK,运行可选JRE,现JDK已集成JRE... 目录为什么要安装jdk?1.查看linux系统是否有自带的jdk:2.下载jdk压缩包2.解压3.配置环境

Linux搭建ftp服务器的步骤

《Linux搭建ftp服务器的步骤》本文给大家分享Linux搭建ftp服务器的步骤,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录ftp搭建1:下载vsftpd工具2:下载客户端工具3:进入配置文件目录vsftpd.conf配置文件4:

Linux实现查看某一端口是否开放

《Linux实现查看某一端口是否开放》文章介绍了三种检查端口6379是否开放的方法:通过lsof查看进程占用,用netstat区分TCP/UDP监听状态,以及用telnet测试远程连接可达性... 目录1、使用lsof 命令来查看端口是否开放2、使用netstat 命令来查看端口是否开放3、使用telnet

Linux系统管理与进程任务管理方式

《Linux系统管理与进程任务管理方式》本文系统讲解Linux管理核心技能,涵盖引导流程、服务控制(Systemd与GRUB2)、进程管理(前台/后台运行、工具使用)、计划任务(at/cron)及常用... 目录引言一、linux系统引导过程与服务控制1.1 系统引导的五个关键阶段1.2 GRUB2的进化优

Unity新手入门学习殿堂级知识详细讲解(图文)

《Unity新手入门学习殿堂级知识详细讲解(图文)》Unity是一款跨平台游戏引擎,支持2D/3D及VR/AR开发,核心功能模块包括图形、音频、物理等,通过可视化编辑器与脚本扩展实现开发,项目结构含A... 目录入门概述什么是 UnityUnity引擎基础认知编辑器核心操作Unity 编辑器项目模式分类工程

Linux查询服务器 IP 地址的命令详解

《Linux查询服务器IP地址的命令详解》在服务器管理和网络运维中,快速准确地获取服务器的IP地址是一项基本但至关重要的技能,下面我们来看看Linux中查询服务器IP的相关命令使用吧... 目录一、hostname 命令:简单高效的 IP 查询工具命令详解实际应用技巧注意事项二、ip 命令:新一代网络配置全

linux安装、更新、卸载anaconda实践

《linux安装、更新、卸载anaconda实践》Anaconda是基于conda的科学计算环境,集成1400+包及依赖,安装需下载脚本、接受协议、设置路径、配置环境变量,更新与卸载通过conda命令... 目录随意找一个目录下载安装脚本检查许可证协议,ENTER就可以安装完毕之后激活anaconda安装更