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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/458858.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NModbus的NuGet包使用样例

首先仿真软件ModbusSlave简单配置3条数据&#xff1a; 连接配置&#xff1a; VS中安装NuGet包&#xff1a;NModbus4 简单获取湿度 SerialPort serialPort new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);serialPort.Open();Modbus.Device.ModbusSer…

mysql项目实战,常用sql语句的实战笔记

1.使用sql语句对数据库进行创建 //创建实验用的数据库 CREATE DATABASE jsschool;//使用当前数据库 USE jsschool;//创建学生表 CREATE TABLE student (sno VARCHAR(20) PRIMARY KEY COMMENT 学生编号,sname VARCHAR(20) NOT NULL COMMENT 学生姓名,ssex VARCHAR(10) NOT NULL…

WebSocket相关问题

1.WebSocket是什么&#xff1f;和HTTP的区别&#xff1f; WebSocket是一种基于TCP连接的全双工通信协议&#xff0c;客户端和服务器仅需要一次握手&#xff0c;两者之间就可以创建持久性的连接&#xff0c;并且支持双向数据的传输。WebSocket和HTTP都是基于TCP的应用层协议&am…

解决: 0x803f7001 在运行Microsoft Windows 非核心版本的计算机上,运行“ slui.exe 0x2a 0x803f7001 “以显示错误文本,激活win10步骤流程。

一. 解决 0x803F7001在运行Microsoft Windows非核心版本的计算机错误 首先&#xff0c;按下winR打开"运行",输入 regedit 后回车&#xff0c;打开注册表。   然后再注册表下输入地址HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProt…

YOLO部署实战(2):使用OpenCV优化视频转图片流程并设置帧数

在计算机视觉和图像处理领域&#xff0c;OpenCV是一个强大的开源库&#xff0c;它为处理图像和视频提供了丰富的工具和功能。本文将介绍如何使用OpenCV将视频文件转换为一系列图片&#xff0c;并演示如何通过设置转换的帧数来优化这一过程。 1 Win10配置OpenCV 在Windows操作…

开源项目的三年,我的项目经历了哪些变化?

0.前言 自己一个项目写了三年&#xff0c;到底写了什么东西了&#xff0c;这个项目经历了哪些变化呢&#xff1f;其中的心路历程如何&#xff1f; 兄弟们&#xff0c;要是感觉我的项目有价值&#xff0c;去b站给俺点点关注呐。我更新的更快。点击下面的了解就可以跳转去b站。…

水面漂浮物监测识别摄像机

水面漂浮物监测识别摄像机是一种用于监测水域表面上漂浮物的设备&#xff0c;可以帮助环保部门或海洋研究机构快速发现和识别水中的浮游物&#xff0c;有助于保护水质和生态环境。这种摄像机通常具有以下功能和特点&#xff1a; 高分辨率摄像头&#xff1a;配备高清晰度摄像头&…

ongoDB从入门到实战之.NET Core使用MongoDB开发ToDoList系统(2)-Swagger框架集成

Swagger是什么&#xff1f; Swagger是一个规范且完整API文档管理框架&#xff0c;可以用于生成、描述和调用可视化的RESTful风格的 Web 服务。Swagger 的目标是对 REST API 定义一个标准且和语言无关的接口&#xff0c;可以让人和计算机拥有无须访问源码、文档或网络流量监测就…

算法练习-删除二叉搜索树中的节点(思路+流程图+代码)

难度参考 难度&#xff1a;中等 分类&#xff1a;二叉树 难度与分类由我所参与的培训课程提供&#xff0c;但需要注意的是&#xff0c;难度与分类仅供参考。且所在课程未提供测试平台&#xff0c;故实现代码主要为自行测试的那种&#xff0c;以下内容均为个人笔记&#xff0c;旨…

第三百一十三回

文章目录 1. 概念介绍2. 实现方法2.1 obscureText属性2.2 decoration属性 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何实现倒计时功能"相关的内容&#xff0c;本章回中将介绍如何实现密码输入框.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍…

【JS逆向七】逆向某翻译网站的sign参数,并模拟生成 仅供学习

逆向日期&#xff1a;2024.02.07 使用工具&#xff1a;Node.js 文章全程已做去敏处理&#xff01;&#xff01;&#xff01; 【需要做的可联系我】 可使用AES进行解密处理&#xff08;直接解密即可&#xff09;&#xff1a;AES加解密工具 1、打开某某网站(请使用文章开头的AES…

洛谷C++简单题小练习day9—[AHOI2017]寻找探监点

day9--[AHOI2017]寻找探监点--2.7 习题概述 题目描述 一个nn 的网格图&#xff08;标号由 1,1 开始&#xff09;上有 m 个探测器&#xff0c;每个探测器有个探测半径 r &#xff0c;问这 nn 个点中有多少个点能被探测到。 输入格式 第一行 3 个整数 n,m,r。 接下来 m 行&…