C库函数

        Linux的系统I/O函数(read、write、open、close和 lseek等)与C语言的C库函数(libc.so库文件中)都是相对应的,它们都是动态库函数。如下图所示,C库函数有fopen、fclose、fwrite、fread和fseek等。这些C库函数都封装在libc.so库文件中,其中的fopen函数用于打开一个文件,其返回值为FILE *类型(指向FILE类型的一个指针),FILE类型为一个结构体,用于描述对打开的文件的一些操作,对于除了fopen以外的C库函数都会通过这个FILE *类型指针对打开的文件进行操作。

FILE类型为一个结构体,包括三个部分:文件描述符、文件读写指针和I/O缓冲区。

文件描述符(整型)用于索引到对应的磁盘文件,类似于FCB(文件控制块)和索引结点,包含了该文件在磁盘上的位置信息。对于每一个进程打开的所有文件在其PCB中都有记录相应的文件描述符,如0代表标准输入,其宏定义为STDIN_FILENO(#define STDIN_FILENO 0)。所有执行I/O操作的系统调用都以文件描述符,即一个非负整数来指代所打开的文件。文件描述符可以用来表示所有类型的已打开文件。同时,多个文件描述符可以指向同一个打开文件,因为有在不同进程中打开同一个文件的需求。

文件描述符是一个整型数,文件描述符表是一个整型数组,而在PCB中有一个指针,指向文件描述符表的首地址,因此根据PCB就可以找到对应的文件描述符,而每一个文件描述符都对应一个FILE *的指针,即可以根据文件描述符进一步找到FILE结构体,该结构体保存了所打开文件的属性信息(文件大小、I/O缓冲、读写指针、文件打开次数等等),而这样的结构体每个文件都只有一份,供所有打开该文件的进程共享,而这些进程所不同的只是文件描述符不一样。FILE结构体的内容只有一份。FILE结构体类似inode,而文件描述符类似简化的FCB。

每一个文件只有一个文件读写指针(读写文件过程中指针的实际位置),在文件读写时要时刻注意当前文件指针的位置。文件读写指针指向将要写入或读出的下一个地址。如果一个进程对文件正在进行写入,此时另一个进程要读取该文件的数据,需要利用fseek函数将文件读写指针置于文件的起始位置才能读取数据。

系统调用指操作系统提供给用户程序调用的一组接口(接口函数)来获得内核提供的服务。在实际中程序员使用的通常不是系统调用,而应用程序接口API,也称为系统调用编程接口,接口函数可能要一个或者几个系统调用才能完成函数功能,此函数通过c库(libc)实现,如fread,fopen等。

I/O缓冲区。每一个C库函数在对文件操作时都会有对应的I/O缓冲区,I/O缓冲区属于内存的一部分,位于用户空间,默认大小为8KB,即8192个Bytes。

以fgetc / fputc函数为例,当用户程序第一次调用fgetc 读一个字节时,fgetc函数可能通过系统调用进入内核读1K字节到I/O缓冲区中,然后返回I/O缓冲区中的第一个字节给用户,把读写位置指向I/O缓冲区中的第二个字符,以后用户再调fgetc ,就直接从I/O缓冲区中读取,而不需要进内核了,当用户把这1K字节都读完之后,再次调用fgetc时,fgetc 函数会再次进入内核读1K字节到I/O缓冲区中。C标准库之所以会从内核预读一些数据放 在I/O缓冲区中,是希望用户程序随后要用到这些数据,C标准库的I/O缓冲区也在用户空间,直接从用户空间读取数据比进内核读数据要快得多。另一方面,用户程序调用fputc通常只是写到I/O缓冲区中,这样fputc 函数可以很快地返回,如果I/O缓冲区写满了,fputc 就通过系统调用把I/O缓冲区中的数据传给内核,内核最终把数据写回磁盘或设备。有时候用户程序希望把I/O缓冲区中的数据立刻给内核,让内核写回设备或磁盘,这称为Flush操作,对应的库函数是fflush,fclose函数在关闭文件之前也会做Flush操作。

由上可以看出,fgetc和fputc库函数在完成工作的过程中可能需要几个系统调用,如将I/O缓冲区的数据写入内核缓冲,将内核缓冲数据刷到磁盘上等。因此,通过增设I/O缓冲区和内核缓冲可以减少进入内核的次数和对磁盘的操作次数(这些都需要系统调用来完成),从而提高了读写效率。相对于内存,机械硬盘的读写速度很慢。机械硬盘的读写寻道时间ms级,而内存的读写速度是ns级别。另外,从用户空间(I/O缓冲区)直接读写数据也会比进入内核(系统调用)要快很多。

Flush操作。指把I/O缓冲区的数据立即传送给内核,然后刷到磁盘上,分为强制性和非强制性两种。C库函数fflush是强制性把I/O缓冲区的数据立即写给内核的缓冲区;C库函数fsync是强制性把内核缓冲区的数据立即刷到磁盘上。main函数的return和调用main函数中的exit(退出当前进程),也会把缓冲区的数据立即写到磁盘上。I/O缓冲区已经写满或者关闭文件时,将会自动将其数据写到磁盘上。

内核缓冲区。人生三大错觉之中的一个:在调用函数write()时,我们觉得该函数一旦返回,数据便已经写到了文件里,可是这样的概念仅仅是宏观上的。实际上,操作系统实现某些文件I/O时(如磁盘文件),为了保证I/O的效率,在内核一般会用到一片专门的区域(内存或独立的I/O地址空间)作为I/O数据缓冲区.它用在输入输出设备和CPU之间,用来缓存数据,使得低速的设备和快速的CPU可以协调工作避免低速的输入输出设备长时间占用CPU,降低系统调用,提高了CPU的工作效率。

Linux系统I/O函数是没有I/O缓冲区的,其缓存是由用户提供的。C库函数都有对应的I/O缓冲区8KB(8196Bytes)。注意:内核缓冲和I/O缓冲的作用不同

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

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

相关文章

【Leetcode | 48】226. 翻转二叉树

翻转一棵二叉树。 示例: 输入: 4 / \ 2 7 / \ / \ 1 3 6 9 输出: 4 / \ 7 2 / \ / \ 9 6 3 1 备注: 这个问题是受到 Max Howell 的 原问题 启发的 : 谷歌:我们90%的…

C库函数与Linux系统函数之间的关系

由上小节知道,C库函数是借助FILE类型的结构体来对文件进行操作的,其本身只是在用户空间(I/O缓冲区)进行读写操作,而数据在内核与用户空间之间的传递、以及将内核与I/O设备之间的数据传递都是该C库函数进行一系列的系统…

【第十六章】模板实参推断

二、模板显式推断 在C中&#xff0c;若函数模板返回类型需要用户指定&#xff0c;那么在定义函数模板时&#xff0c;模板参数的顺序是很重要的&#xff0c;如下代码&#xff1a; template <typename T1, typename T2, typename T3> //模板一 T1 sum(T2 a, T3 b) {retu…

open函数和errno全局变量

&#xff08;1&#xff09;open函数 man man 查看man文档的首页 其中DESCRIPTION部分描述了man文档的每一章的章节内容 第2章System calls为系统调用&#xff0c;即Liunx系统函数。 man 2 open 查看第二章的open函数的详细帮助文件。 open函数用于打开一个已经的文件或者创…

open函数和close函数的使用

学习几个常用的Linux系统I/O函数&#xff1a;open、close、write、read和lseek。注意&#xff0c;系统调用函数必须都考虑返回值。 &#xff08;1&#xff09;open函数的使用 首先&#xff0c;需要包含三个头文件&#xff1a;<sys/types.h> <sys/stat.h> <…

【Leetcode | 9】217. 存在重复元素

解题代码&#xff1a; bool containsDuplicate(vector<int>& nums) {return nums.size() > set<int>(nums.begin(), nums.end()).size(); }

全缓冲、行缓冲和无缓冲

这里的缓冲是指的是用户空间的I/O缓冲区&#xff0c;不是内核缓冲。 无缓冲&#xff1a;用户层不提供缓冲&#xff0c;数据流直接到内核缓冲&#xff0c;再到磁盘等外设上。标准错误输出&#xff08;2&#xff09;通常是无缓存的&#xff0c;因为它必须尽快输出&#xff0c;且…

【Leetcode】1. 两数之和

给定一个整数数组 nums 和一个目标值 target&#xff0c;请你在该数组中找出和为目标值的那 两个 整数&#xff0c;并返回他们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;你不能重复利用这个数组中同样的元素。 示例: 给定 nums [2, 7, 11, 15], targ…

read和write函数的使用

都需要包含头文件&#xff1a; <unistd.h> read系统函数从打开的设备或文件中读取数据&#xff0c;即将数据从外设上经过内核读到用户空间&#xff1b;write系统函数相反&#xff0c;向打开的设备或文件中写入数据&#xff0c;即将数据从用户空间&#xff08;I/O缓冲&am…

1091. Acute Stroke (30)

One important factor to identify acute stroke (急性脑卒中) is the volume of the stroke core. Given the results of image analysis in which the core regions are identified in each MRI slice, your job is to calculate the volume of the stroke core. Input Speci…

lseek函数的使用

需要包含头文件&#xff1a;<sys/types.h> <unistd.h> off_t lseek(int fd, off_t offset, int whence)&#xff1b; 函数原型 函数功能&#xff1a;移动文件读写指针&#xff1b;获取文件长度&#xff1b;拓展文件空间。 在使用该函数之前需要将文件打开&…

19. 删除链表的倒数第N个节点

给定一个链表&#xff0c;删除链表的倒数第 n 个节点&#xff0c;并且返回链表的头结点。 示例&#xff1a; 给定一个链表: 1->2->3->4->5, 和 n 2. 当删除了倒数第二个节点后&#xff0c;链表变为 1->2->3->5. 说明&#xff1a; 给定的 n 保证是有效的。…

文件操作相关的系统函数

重点学习&#xff1a;stat&#xff08;fstat、lstat 获取文件属性&#xff09;、access&#xff08;测试指定文件是否拥有某种权限&#xff09;、chmod&#xff08;改变文件的权限&#xff09;、chown&#xff08;改变文件的所属主和所属组&#xff09;、truncate&#xff08;截…

stat函数(stat、fstat、lstat)

#include <sys/types.h> #include <sys/stat.h> #include <unistd.h> //需包含头文件 有如下三个函数的函数原型&#xff1a; int stat(const char *path, struct stat *buf); 第一个形参&#xff1a;指出文件&#xff08;文件路径&#xff09;&…

1062. Talent and Virtue (25)

About 900 years ago, a Chinese philosopher Sima Guang wrote a history book in which he talked about peoples talent and virtue. According to his theory, a man being outstanding in both talent and virtue must be a "sage&#xff08;圣人&#xff09;"…

access、strtol函数的使用(后者为C库函数)

#include <unistd.h> int access(const char *pathname, int mode); 作用&#xff1a;检查调用该函数的进程是否可以对指定的文件执行某种操作。 第一个形参&#xff1a;文件名&#xff1b;第二个形参&#xff1a;R_OK&#xff08;是否可读&#xff09;、W_OK&#xf…

chmod、chown函数的使用

#include <sys/stat.h> int chmod(const char *path, mode_t mode); int fchmod(int fd, mode_t mode); 作用&#xff1a;改变指定文件的权限。第二个参数&#xff1a;mode必须为一个8进制数&#xff1b;返回值为0表示成功&#xff0c;-1表示失败。 //代码 #include…

606. 根据二叉树创建字符串

你需要采用前序遍历的方式&#xff0c;将一个二叉树转换成一个由括号和整数组成的字符串。 空节点则用一对空括号 "()" 表示。而且你需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。 示例 1: 输入: 二叉树: [1,2,3,4] 1 / \ …

truncate、rename函数的使用

#include <unistd.h> #include <sys/types.h> int truncate(const char *path, off_t length); int ftruncate(int fd, off_t length); 作用&#xff1a;用于拓展或截断文件。将参数path 指定的文件大小改为参数length 指定的大小。如果原来的文件大小比参数le…

【Leetcode】112. 路径总和

给定一个二叉树和一个目标和&#xff0c;判断该树中是否存在根节点到叶子节点的路径&#xff0c;这条路径上所有节点值相加等于目标和。 说明: 叶子节点是指没有子节点的节点。 示例: 给定如下二叉树&#xff0c;以及目标和 sum 22&#xff0c; 5 / \ …