简介几种系统调用函数:write、read、open、close、ioctl
在 Linux 中,一切(或几乎一切)都是文件,因此,文件操作在 Linux 中是十分重要的,为此,Linux 系统直接提供了一些函数用于对文件和设备进行访问和控制,这些函数被称为系统调用(syscall),它们也是通向操作系统本身的接口。
一、系统调用
系统调用就是 Linux 内核提供的一组用户进程与内核进行交互的接口。这些接口让应用程序受限的访问硬件设备,提供了创建新进程并与已有进程进行通信的机制,也提供了申请操作系统其他资源的能力。
系统调用工作在内核态,实际上,系统调用是用户空间访问内核空间的唯一手段(除异常和陷入外,它们是内核唯一的合法入口)。系统调用的主要作用如下:
1)系统调用为用户空间提供了一种硬件的抽象接口,这样,当需要读写文件时,应用程序就可以不用管磁盘类型和介质,甚至不用去管文件所在的文件系统到底是哪种类型;
2)系统调用保证了系统的稳定和安全。作为硬件设备和应用程序之间的中间人,内核可以基于权限、用户类型和其他一些规则对需要进行的访问进行判断;
3)系统调用是实现多任务和虚拟内存的前提。
要访问系统调用,通常通过 C 库中定义的函数调用来进行。它们通常都需要定义零个、一个或几个参数(输入),而且可能产生一些副作用(会使系统的状态发生某种变化)。系统调用还会通过一个 long 类型的返回值来表示成功或者错误。通常,用一个负的值来表明错误,0表示成功。系统调用出现错误时,C 库会把错误码写入 errno 全局变量,通过调用 perror() 库函数,可以把该变量翻译成用户可理解的错误字符串。
二、几种常用的系统调用函数
2.1 write 系统调用
系统调用 write 的作用是把缓冲区 buf 的前 nbytes 个字节写入与文件描述符 fildes 关联的文件中。它返回实际写入的字节数。如果文件描述符有错或者底层的设备驱动程序对数据块长度比较敏感,该返回值可能会小于 nbytes。如果函数返回值为 0,就表示没有写入任何数据;如果返回值为 -1,则表明 write 系统调用出现了错误,错误代码保存在全局变量 errno 里。 write 系统调用的原型如下:
#include <unistd.h> size_t write(int fildes,const void *buf,size_t nbytes);
其中,size_t 是标准 C 库中定义的一个数据类型,实际上就是 unsigned int。
fildes 是文件描述符,内核利用文件描述符来访问文件,它是一个非负的整数,当打开现存文件或者新建一个文件时,都会返回一个文件描述符。有多少文件描述符取决于系统的配置情况,当一个程序开始运行时,它一般有 3 个已经打开的文件描述符:标准输入 0;标准输出 1;标准错误 2。
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h> int main()
{
size_t x = write(,"my name is tongye!\n",);
printf("you have writed %d words to the buffer\n",x); exit();
} /* 输出结果:
my name is tongye!
you have writed 20 words to the buffer
*/
这段代码简单演示了一下 write 系统调用函数的用法:从缓冲区 buffer 中读取前 20 个字节写入标准输出中,write 返回了实际写入的字节数。
2.2 read 系统调用
系统调用 read 的作用是:从文件描述符 fildes 相关联的文件里读入 nbytes 个字节的数据,并把它们放到数据区 buf 中。它返回实际读入的字节数,这可能会小于请求的字节数。如果 read 调用返回 0,就表示没有读入任何数据,已到达了文件尾;如果返回 -1,则表示 read 调用出现了错误。read 系统调用的原型如下:
#include <unistd.h> size_t read(int fildes,void *buf,size_t nbytes);
用一段代码演示一下用法:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h> int main()
{
char buffer[];
size_t x = read(,buffer,);
write(,buffer,x); exit();
} /* 输出结果:
hello ,my name is tongye!
hello ,my name is tongye!
*/
这段代码使用 read 系统调用函数从标准输入读取 30 个字节到缓冲区 buffer 中去(输出结果中的第一行是从标准输入键入的),然后使用 write 系统调用函数将 buffer 中的字节写到标准输出中去。
2.3 open 系统调用
系统调用 open 用于创建一个新的文件描述符。
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h> int open(const char *path,int oflags);
int open(const char *path,int oflags,mode_t mode); // oflags 标志为 O_CREAT 时,使用这种格式
open 建立了一条到文件或设备的访问路径。如果调用成功,它将返回一个可以被 read、write 和其他系统调用使用的文件描述符。这个文件描述符是唯一的,不会与任何其他运行中的进程共享。在调用失败时,将返回 -1 并设置全局变量 errno 来指明失败的原因。
使用 open 系统调用时,准备打开的文件或设备的名字作为参数 path 传递给函数,oflags 参数用于指定打开文件所采取的动作。oflags 参数是通过命令文件访问模式与其他可选模式相结合的方式来指定的,open 调用必须指定以下文件访问模式之一:
1)O_RDONLY:以只读方式打开;
2)O_WRONLY:以只写方式打开;
3)O_RDWR :以读写方式打开。
另外,还有以下几种可选模式的组合( 用按位或 || 来操作 ):
4)O_APPEND:把写入数据追加在文件的末尾;
5)O_TRUNC:把文件长度设置为零,丢弃已有的内容;
6)O_CREAT:如果需要,就按照参数 mode 中给出的访问模式创建文件;
7)O_EXCL:与 O_CREAT 一起使用,确保调用者创建出文件。使用这个模式可以防止两个程序同时创建同一个文件,如果文件已经存在,open 调用将失败。
当使用 O_CREAT 标志的 open 调用来创建文件时,需要使用有 3 个参数格式的 open 调用。其中,第三个参数 mode 是几个标志按位或后得到的,这些标志在头文件 sys/stat.h 中定义,如下:
标志 | 说明 | 标志 | 说明 | 标志 | 说明 |
S_IRUSR | 文件属主可读 | S_IRGRP | 文件所在组可读 | S_IROTH | 其他用户可读 |
S_IWUSR | 文件属主可写 | S_IWGRP | 文件所在组可写 | S_IWOTH | 其他用户可写 |
S_IXUSR | 文件属主可执行 | S_IWOTH | 文件所在组可执行 | S_IXOTH | 其他用户可执行 |
用一个例子说明一下:
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h> int main()
{
open("file",O_CREAT,S_IRUSR | S_IWGRP); exit();
}
执行这段代码将在当前目录下创建一个名为 file 的文件,该文件对文件属主可读,对文件所在组可写,用 ls -l 命令查看如下:
可以看到有一个名为 file 的文件,该文件就是使用 open 系统调用创建的,文件的权限为文件属主可读,文件所在组可写。
2.4 close 系统调用
系统调用 close 可以用来终止文件描述符 fildes 与其对应文件之间的关联。当 close 系统调用成功时,返回 0,文件描述符被释放并能够重新使用;调用出错,则返回 -1。
#include <unistd.h> int close(int fildes);
2.5 ioctl 系统调用
系统调用 ioctl 提供了一个用于控制设备及其描述符行为和配置底层服务的接口。终端、文件描述符、套接字甚至磁带机都可以有为它们定义的 ioctl。
#include <unistd.h> int ioctl(int fildes,int cmd,...);
ioctl 对描述符 fildes 引用的对象执行 cmd 参数中给出的操作。
参考资料:
《Linux程序设计 第四版》
简介几种系统调用函数:write、read、open、close、ioctl的更多相关文章
- (转)linux下的系统调用函数到内核函数的追踪
转载网址:http://blog.csdn.net/maochengtao/article/details/23598433 使用的 glibc : glibc-2.17使用的 linux kerne ...
- <<一种基于δ函数的图象边缘检测算法>>一文算法的实现。
原始论文下载: 一种基于δ函数的图象边缘检测算法. 这篇论文读起来感觉不像现在的很多论文,废话一大堆,而是直入主题,反倒使人觉得文章的前后跳跃有点大,不过算法的原理已经讲的清晰了. 一.原理 ...
- Javascript学习笔记:3种定义函数的方式
①使用函数声明语法定义函数 function sum(num1,num2){ return num1+num2; } ②使用函数表达式定义函数 var sum=function(num1,num2){ ...
- js两种定义函数、继承方式及区别
一:js两种定义函数的方式及区别 1:函数声明: function sayA() { alert("i am A"); } 2:函数表达式: var sayB = function ...
- SQL中的5种聚集函数
作为一个刚毕业进入这行的菜鸟,婶婶的觉的那种大神.大牛到底是怎样炼成的啊,我这小菜鸟感觉这TMD要学的东西这多啊,然后就给自己定了许多许多要学习的东西,可是有人又不停地给你灌输:东西不在多而要精通!我 ...
- javascript两种声明函数的方式的一次深入解析
声明函数的方式 javascript有两种声明函数的方式,一个是函数表达式定义函数,也就是我们说的匿名函数方式,一个是函数语句定义函数,下面看代码: /*方式一*/ var FUNCTION_NAME ...
- 【Linux】文件操作函数(系统调用函数)
重点在于学习--思路与方法 举一反三 一.文件描述符 系统分配给文件的数字编号 二.函数学习 P.S.Man命令使用方法 manual 前三个章节 命令:系统调用函数:库函数 man read //r ...
- 两种const函数
有两种const函数,声明如下:1.const T func();2.T func() const;第一种表示返回的是const的类型,也即返回的值不能作为左值,楼主懂的.第二种表示该成员函数不能修改 ...
- [教程]Delphi 中三种回调函数形式解析
Delphi 支持三种形式的回调函数 全局函数这种方式几乎是所有的语言都支持的,类的静态函数也可以归为此类,它保存的只是一个函数的代码起始地址指针( Pointer ).在 Delphi 中声明一般为 ...
随机推荐
- 【转】iOS - SQLite 数据库存储
本文目录 1.SQLite 数据库 2.iOS 自带 SQLite 的使用 3.fmdb 的使用 4.fmdb 多线程操作 5.其他 SQLite 的第三方封装库 回到顶部 1.SQLite 数据库 ...
- List集合的子类ArrayList和LinkedList
一: 我们常用对集合的操作,查询.增删等操作. 由于集合的存储的方式的不同,导致有些集合查询快但是增删慢.有些集合增删快.但是查询慢. ArrayList:由于ArrayList存储的方式为数组形式. ...
- “unauthorized: authentication required” -- openshift3.9 docker push 报错
1.docker tag mybank-tomcat:latest 172.30.25.185:5000/mybank-tomcat:latest 2.当往registrypush镜像的时候, doc ...
- <摘录>字节对齐与结构体大小
说明: 结 构体的sizeof值,并不是简单的将其中各元素所占字节相加,而是要考虑到存储空间的字节对齐问题.这些问题在平时编程的时候也确实不怎么用到,但在一 些笔试面试题目中出是常常出现,对sizeo ...
- 更改KVM虚拟机root的密码
今天在使用qemu-kvm安装一个虚拟机,因为已经有一个虚拟机的image文件(qcow2格式的),所以创建虚拟机很简单,直接通过以下命令从image启动就行了. qemu-kvm -cpu host ...
- 快速开发平台分享-UCML快速开发七种武器
传统的快速开发平台强调的是组件重用.构件重用,主要解决功能重用层面,一般提供了软件开发最常用的功能:表单设计.BPM(业务流程管理).报表.组织机构及权限等功能.但只有功能重用,没有过程重用,要么只能 ...
- 微信支付JsApi 40163错误
微信支付JsApi 40163错误错误:未定义数组索引:openid .经过检查发现是 :微信支付授权获取 openId {“errcode”:40163,“errmsg”:“code been us ...
- day 84 Vue学习四之过滤器、钩子函数、路由、全家桶等
本节目录 一 vue过滤器 二 生命周期的钩子函数 三 vue的全家桶 四 xxx 五 xxx 六 xxx 七 xxx 八 xxx 一 Vue的过滤器 1 moment.js 在这里我们先介绍一个 ...
- go lang中局部变量的内存分配
晚上在阅读go lang的资料时突然想到一个问题,go是如何分配变量的内存结构的呢?好在网上的一篇文章做了透彻的分析见[go语言局部变量分配在栈还是堆]. 其结论是go语言局部变量的分配是由编译器决定 ...
- windowbuilder
windowbuilder,也就是原来的SWT Designer.Google收购了Instantiations,把它的工具也重新免费发布了.用过swt designer的人都知它是非常好用的swin ...