我们可以用系统调用来操作文件,这种方式和I/O库函数各有千秋,我们需要明白库函数在用户地址空间执行,系统调用是在内核地址空间执行,依赖Linux系统,不要搞混了,那我们下面来学习一下。 系统调用是在内核空间执行的,那么我们就需要了解在内核中是如何标识文件的。对于内核而言,所有打开的文件都通过文件描述符(简称fd)引用就是标识。文件描述符是一个非负整数,指代被打开的文件,当打开一个现有的文件或创建一个新文件时,内核向进程返回一个文件描述符,将其作为参数给系统调用的I/O操作。 所以最小的文件描述符从3开始,即打开第一个文件open()返回的文件描述就是3。 sysctl -a | grep fs.file-max 同时,内核为了防止一个进程创建多个文件,占用文件描述符,对单个进程创建文件的上限也做了规定,可以用: ulimit -n 带缓冲区I/O就是在内存开辟缓冲区,当执行读文件操作时,先把磁盘文件读到缓冲区,进行一次读取,再根据程序需要将数据给读给变量。我们上次学的库文件I/O函数就是带缓冲区的,如fopen,fread等。这种特性的好处是和外存的交互次数由缓冲区大小决定,如果缓冲区大,和对外存操作少。如果进入内核读取数据,那么交互次数会少,因为它会尽可能地一次读取数据。故执行速度就快,效率高。 不带缓冲区的I/O就是执行I/O函数时,根据程序需求,直接将数据给变量。不带缓冲区I/O依赖于操作系统,即系统级输入输出,就是我们今天要学习的系统调用I/O,如open等,它会和内核进行多次交互,所以执行速度会慢。 但是我们不能以偏概全,不带缓冲区地read系统调用函数一定比带缓冲区地fread库函数速度慢,这时不对的,只有合适,没有不好。我们知道read需要进行多次内核态和用户态的交互,而fread则交互少,如果我们是顺序读取数据,那么fread即带缓冲区的更快,但是如果我们随机读取数据,这时缓冲区的作用降低,read反而速度快。所以要在一定的情景下来找最合适的。 介绍关于man的指令,方便查看函数的信息: 系统调用是由内核提供的一系列函数,实现时涉及到从用户态进入内核态,那么我们如何进入呢?中断,中断是现代计算机不可或缺的机制。 中断的分类: 由CPU外部引起的,称为中断,如I/O中断等。 由CPU内部事件或程序引起的,称作异常,如数组非法越界等。 由在程序中使用了系统调用而引发的过程,称作陷入。 前两个都是被动的,最后一个是主动的,所以把最后一个也称为软中断。 操作系统处理中断: 操作系统中有一张中断表,称为中断描述符表,它保存着中断向量号(即中断序号),对应的异常事件,需要调用的处理程序这三个信息。硬件中断机制提供了256个入口,即包含了256种中断事件类型,它规定: 我们还需要了解用户栈和内核栈: 那么在程序发生异常或发生系统调用时,陷入内核,产生中断,从用户态到内核态,首先系统会保存现场,将此时所有进程的数据,代码等所有信息保存在内核栈;之后再根据中断的向量号进行中断处理,调用对应的处理程序;最后处理完成后恢复现场,将内核栈信息再还给用户栈,从内核态到用户态。 中断机制是一个很复杂的机制,博主只写了基础知识,如果需要深入了解,自己翻阅资料即可。 那我们介绍一下我们常用的系统调用I/O函数吧。 open()函数打开或创建一个文件,函数原型为: # include<fcntl.h>。 参数说明:第三个参数的形式我们称为可变参数。 还有很多参数,但不常用,就不列举了,多个参数之间使用【|】来连接 read()函数从打开文件中读取数据,函数原型为: # include<unistd.h> 参数含义: 读到那里,文件偏移量就到那里,所以以前读过的要想再读,需要移动文件偏移量。 write()函数向打开的文件写数据,函数原型为: # include<unistd.h> 参数含义: 文件偏移量会随着数据写入而移动。 close()关闭一个打开的文件,函数原型为: # include<unistd.h> 参数说明:files表示文件描述符。成功返回-,失败返回-1。 lseek()为一个打开的文件设置其偏移值,函数原型为: # include<unistd.h> 参数说明: (4)返回值:成功返回新的文件偏移量,出错返回-1。 系统调用是陷入中断,进入内核的过程,是通向操作系统本身的接口,当系统调用I/O函数发生时,内核将调用内核相关函数来实现,如(sys_read(),sys_write()等),系统调用时一个从用户态->内核态->用户态的过程,下面我们来看一下它的过程时怎样的: 那我们简略的画出这个过程,这个只是为了方便理解画出的图,函数和对应的调用号并不是内核中真正的数据。 我们用一下这几个函数,和库函数的例题一样,将界面上输入的数据存储到a.txt中,再将a.txt中的内容显示在终端上,cp拷贝的就不写了,那个只需要替换读写函数即可。这个题目的思路和原来一模一样,不过就是函数变了,取值判断变了,那我们下面来看看代码: 结果: 加油哦!💪。文章目录:
一、基本概念
(一)文件描述符
POSIX标准要求每次打开文件时,必须从小到大申请文件描述符,那么最小的文件描述符是几呢?不是0,因为系统已经规定了前三个:
文件描述符
POSIX名称 (常量定义在头文件<unistd.h>)
用途
stdio流
0
STDIN_FILENO
标准输入
stdin
1
STDOUT_FILENO
标准输出
stdout
2
STDERR_FILENO
标准错误
stderr
那么系统创建文件的上限是多少呢?我们可以使用指令来查看最多可以打开多少个文件:
默认值为1024个。文件创建的上限是可以更改,在这里我就不阐述了,有兴趣的可以去了解。(二)带缓冲区的I/O && 不带缓冲区的I/O
(三)man指令
指令
含义
man 1 command
查看命令的帮助手册
man 2 系统调用
查看系统调用手册
man 2 库函数
查看库函数的使用手册
(四)基础中断机制知识
中断的概念: 中断是指CPU在正常运行程序时,由于内部/外部事件或由程序预先安排引起CPU暂停正在运行的程序,转到引起中断的事件程序中去,处理完毕,再返回到继续执行被暂停的程序。
二、系统调用文件I/O函数
(一)open
int open(const char* pathname,int flags,…/*mode_t*/)
(1)pathname:表示打开或创建文件的路径和名字。
(2)flags:表示打开文件的方式或创建,可以选择的参数为:
参数
含义
选择
O_RDONLY
只读打开
必须指定,但不能和2,3两个参数任何一个同时存在
O_WRONLY
只写打开
必须指定,但不能和1,3两个参数任何一个同时存在
O_RDWR
读写打开
必须指定,但不能和1,2两个参数任何一个同时存在
O_CREAT
若文件不存在则创建它,此时第三个参数有效
可以选择,不要求必须有
O_APPEND
追加到文件末尾
可以选择,不要求必须有
(3)可变参数:只有当参数flags种包含O_CREAT创建文件的常量时,这个参数才存在,它要指定文件的权限,格式为【0xxx】,0是一个标识符,读r权限为4,写w权限为2,执行x权限为1。
(4)返回值:成功返回当前未使用的文件描述符,失败返回-1。(二)read
ssize_t read(int files,void*buf,size_t nbytes);
(1)files:文件描述符。
(2)buf:存储读取到的数据的变量。
(3)nbytes:一次读多少字节。
(4)成功返回读到的字节,到达文件结尾返回0,出错返回-1.(三)write
ssize_t write(int files,const *buf,size_t nbytes);
(1)files:文件描述符;
(2)buf:存储需要写入数据的变量。
(3)nbytes:变量存储数据的长度。
(4)返回值:成功返回已写字节数,出错返回-1。(四)close
int close(int files)
当一个进程终止时,内核自动关闭它所有打开的文件,这个是close的隐式使用,不是显式。(五)lseek
off_t lseek (int files,off_t offset,int whence)
(1)files表示文件描述符。
(2)offset:表示偏移的字节,可正可负和whence参数有关。
(3)whence:表示从哪里开始偏移,可以取值为:
参数
含义
SEEK_SET
将该文件的偏移量设置为距离文件开始处offset字节
SEEK_CUR
将该文件的偏移量设置为距离当前位置处offset字节
SEEK_END
将该文件的偏移量设置为距离末尾处offset字节
三、系统调用的过程
四、例题
# include<stdio.h> # include<stdlib.h> # include<assert.h> # include<string.h> # include<unistd.h> # include<fcntl.h> int main() { int fd=open("./sys.txt",O_RDWR | O_CREAT,0664 ); assert(fd!=-1); while(1)//循环读取数据 { printf("input:"); char buff[128]={0}; fgets(buff,128,stdin);//标准输入 if(strncmp(buff,"end",3)==0) { break; } int n=write(fd,buff,strlen(buff)); if(n<=0) { printf("write error"); exit(0); } } printf("------write over----------n"); int n=lseek(fd,0,SEEK_SET);//重定位 if(n==-1) { printf("lseek error"); exit(0); } while(1) { char buff[128]={0}; int n=read(fd,buff,127); if(n==0) { printf("------read end----------n"); break; } else if(n<0) { printf("read errorn"); exit(0); } else { printf("%s",buff); } } close(fd); exit(0); }
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算