【Linux&Unix--open/close/write/read系统调用】
个人学习整理。如有不足之处,请不吝不吝赐教。
转载请注明:@CSU-Max
系列博文:
Linux&Unix学习第二弹
-- exec 与 fock 系统调用
Linux&Unix学习第三弹
-- open/close/write/read系统调用
在 Unix/Linux 系统中,文件是一个非常重要的概念,本文将介绍 Linux 中和文件相关的几个重要的系统调用--open-close-write-read 系统调用。
open系统调用
函数原型及解释
<span style="font-family:Courier New;font-size:18px;"><span style="font-family:Courier New;font-size:18px;">//open -- 打开或创建文件
int open (
const char *path, /*pathname*/
int flags, /*flags*/
mode_t perms /*permissions (when creating)*/
) ;</span></span>
调用 open能够打开一个已经存在的文件(普通文件、特殊文件或命名管道),或创建一个新文件。但它仅仅能创建普通文件(创建特殊文件须要使用 mknod,命名管道使用 mkfifo)。open返回是打开已存在的文件或创建新文件的文件描写叙述符。文件一旦打开,read、
write、 lseek、 close以及其它调用就能够使用其返回的文件描写叙述符。
打开已存在文件
首先我们来看一下 open函数的三个參数。path是已经存在的文件的路径;至于
flags參数。若值为 O_RDONLY ,就以仅仅读方式打开文件。若值为 O_WDONLY,就以仅仅写方式打开文件,若值为 O_RDWR,就以读写方式打开文件;而对于一个已经存在的文件,參数 perms是没实用的。通常将其省略,因此此种情况下 open调用仅仅需两个參数。
open失败的原因非常多,常见的有例如以下两种:
1.没有对应的文件訪问权限
2.路径所指向的文件不存在
创建新文件
前面已经说到。当文件不存在时,open会创建一个新文件(仅能是普通文件),我们仅仅须要用
or操作向 open的 flags參数中增加标志 O_CREAT就可以。这样能够创建一个新的仅仅读文件,可是这没有不论什么意义,由于所创建的新文件没有不论什么可读内容。
因此一般须要 O_CREAT与 O_WRONLY或
O_RDWR一起使用。此时就须要 perms參数了。
比如:
ec_neg1(
fd = open(“/home/marc/newfile”,O_RDWR | O_CREAT, PERM_FILE) )
參数 perms仅在创建新文件时有效,对于一个已经存在的文件。它没有不论什么作用。
用户有时须要一个新的、没有不论什么数据的文件,即当文件已经存在,须要将其全部数据清除,并设置文件偏移量为0。标志
O_TRUNC能够实现此功能:
ec_neg1(
fd = open(“/home/marc/newfile”,O_WRONLY | O_CREAT | O_TRUNC, PERM_FILE) )
由于 O_TRUNC可以破坏数据。所以仅仅要进程具有写权限,就行清除已存在文件的数据。由于它是写形式的一种。但对于具有
O_RDONLY标志的文件。它就不起作用了。
O_WRONLY| O_CREAT | O_TRUNC这个组合是非经常见的(创建或截短一个具有仅仅写权限的文件),也有专门的相关的系统调用,即
creat系统调用。
creat系统调用
<span style="font-family:Courier New;font-size:18px;"><span style="font-family:Courier New;font-size:18px;">//creat -- 创建或清空文件
int creat (
const char *path, /*pathname*/
mode_t perms /*permissions*/
); </span></span>
採用 open打开一个已经存在的文件仅仅须要第一个參数和第二个參数(path和
flags)。使用 creat创建新文件仅须要第一个參数和第三个參数(path和 perms)。实际上, creat不过一个宏:
#define creat(path, perms) open(path,O_WRONLY | O_CREAT |O_TRUNC, perms)
当然我们也能够仅使用open 而放弃使用
creat,可是在早期,open仅仅有两个參数,那时creat则无可替代。
关于open的flags參数
除了以上介绍的 open标志外,open还有很多标志。详细的例如以下表所看到的:
|
标志 |
解释 |
|
O_RDONLY |
仅仅读方式打开 |
|
O_WRONLY |
仅仅写方式打开 |
|
O_RDWR |
读写方式打开 |
|
O_APPEND |
每次写都追加到文件的尾端 |
|
O_CREAT |
若文件不存在则创建文件 |
|
O_DSYNC |
设置同步I/O方式 |
|
O_EXCL |
假设文件已存在,则出错;必须与O_CREAT一起使用 |
|
O_NOCTTY |
不将此设备作为控制终端 |
|
O_NONBLOCK |
不等待命名管道或特殊文件准备好 |
|
O_RSYNC |
设置同步I/O方式 |
|
O_SYNC |
设置同步I/O方式 |
|
O_TRUNC |
将其长度截短为0 |
close系统调用
函数原型及解释
<span style="font-family:Courier New;font-size:18px;"><span style="font-family:Courier New;font-size:18px;">//close -- 关闭文件描写叙述符
int close (
int fd /*file descriptor*/
);</span></span>
通过对 close进行分析,我们会发现close并没有做什么实质工作,它没有刷新不论什么内核缓冲区,而不过使文件描写叙述符能够重用。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X21heA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast">
如上图,当指向一个打开文件描写叙述的全部文件描写叙述都关闭时。将删除该打开文件描写叙述。
相同的。当指向一个信息节点的全部打开文件描写叙述都被删除时,将删除该内存信息节点。
write系统调用
函数原型及解释
<span style="font-family:Courier New;font-size:18px;"><span style="font-family:Courier New;font-size:18px;">//write -- 向文件描写叙述符写
ssize_t write (
int fd, /*file descriptor*/
const void *buf, /*data to write*/
size_t nbytes /*amount to write*/
); </span></span>
write系统调用将 buf所指向的缓冲区的
n字节写入 fd 所描写叙述ude打开文件里。
写操作从文件偏移量的当前位置開始运行。而且在完毕之后,文件偏移量将添加所写入的字节数。若写入成功,返回值为已写入的字节数,出错则为
-1。
若设置了O_APPEND标志,写入前文件偏移量自己主动定位到文件的结尾。
本文仅讨论普通文件的写操作。
注:write也用与向管道,特殊文件和套接字写入数据,可是情况会有些不同,这些写操作能够堵塞(如它们可能正在等待可用数据)。假设堵塞了写操作,那么到达的信号会中断其操作。
这样的情况下写操作将返回-1。并将
errno设置为 EINTR。
write的真面目
看了前面的介绍,write似乎仅仅是写入数据,接着返回结果。
实际上并不是如此。
当用户调用
write系统调用时并不运行写操作,紧接着返回数据。它不过将数据传递给内核的缓冲区。
当接收到 write请求时,先确保传入的文件描写叙述符能够使用,接着将数据拷贝到内核中的缓冲区。以后。在某个方便的时候,系统会设法把这部分的数据写入磁盘中。
若发现错误,就会设法在控制台输出错误,可是该进程不会返回这个错误(可能此时其已经终止执行了)。若在系统向磁盘写出这些数据之前,该进程或其它进程试图要读取这些数据,那么系统将从内核缓冲区为你读取这些数据。
总而言之。该进程不知道系统什么时候完毕了请求。也不知道是否完毕了请求。假设在该部分缓冲区的数据写出磁盘之前,有磁盘错误。或者因为某种原因内核停止了,那么你会发现要写的数据根本没有写到磁盘上,即使
write 没有报错。
由此我们能够看出,这是一种延迟写。那么延迟写有哪些我们须要关心的问题呢?
1.不能确定什么时候发生物理写操作
2.一个调用写操作的进程没有得到写错误的通知
3.物理写操作的顺序是无法操作的
writeall函数
writeall是一个很方便有用的函数。当须要确保写入全部的内容时,能够使用此函数。
<span style="font-family:Courier New;font-size:18px;"><span style="font-family:Courier New;font-size:18px;">//writeall
ssize_t writeall(int fd, const void *buf, size_t nbyte)
{
ssize_t nwritten = 0; //总共写出的字符数
sszie_t n; //每次 write 操作写出的字符数 do{
if((n = write(fd, &((const char *)buf)[nwriten], nbyte - nwritten)) == -1)
{
if(errno == EINTR) //堵塞时持续循环写出
continue;
else
return -1;
}
nwritten += n;
}while(nwritten < nbyte);
return nwritten;
}</span></span>
read系统调用
函数原型及解释
<span style="font-family:Courier New;font-size:18px;"><span style="font-family:Courier New;font-size:18px;">//read -- 从文件描写叙述符中读入
ssize_t read (
int fd, /*file descriptor*/
void *buf, /*address to receive data*/
size_t nbytes /*amount to read*/
); </span></span>
read系统调用与 write相反,它是从 fd所描写叙述的打开文件里读取
buf所指缓冲区中的 n个字节。read从当前文件偏移量開始读数据,而且完毕读操作后,文件偏移量将添加所读字节数。read的返回值是所读字节数、文件结束标志或者错误标志-1。
读操作不受 O_APPEND标志的影响。
假设数据已经不在缓冲区中(因为曾经的I/O操作),进程必须等待内核从磁盘得到数据。
与 write一样,从管道、特殊文件或套接字中读取数据时,read能够堵塞。
此时读操作可能会被信号中断,结果返回值为-1,并把
errno 设置成 EINTR。
readall函数
类比 writeall函数,假设须要读全部的数据,则通过循环调用
read。readall函数就是这种一个很方便有用的函数。
<span style="font-family:Courier New;font-size:18px;"><span style="font-family:Courier New;font-size:18px;">//readall
ssize_t readall(int fd, const void *buf, size_t nbyte)
{
ssize_t nread == 0; //总共读取的字符数
ssize_t n; //每次 read 操作读取的字符数 do{
if((n = read(fd, &((const char *)buf)[nread], nbyte - nread)) == -1)
{
if(errno == EINTR) //堵塞时持续循环读取
continue;
else
return -1;
}
nread += n;
}while(nread < nbyte);
return nread;
}</span></span>
****************************************************************
* 转载请注明出处: @CSU-Max http://blog.csdn.net/csu_max
*
****************************************************************
【Linux&Unix--open/close/write/read系统调用】的更多相关文章
- Linux 编程中的API函数和系统调用的关系【转】
转自:http://blog.chinaunix.net/uid-25968088-id-3426027.html 原文地址:Linux 编程中的API函数和系统调用的关系 作者:up哥小号 API: ...
- Linux或UNIX系统配置检查
1. Linux或UNIX系统配置检查 系统配置的扫描是基于被动式策略进行扫描,主要检测主机上是否存在配置错误或者不符合预定义的安全策略的配置,通常需要管理员权限才能执行的扫描. 在Linux或UNI ...
- linux和 unix 介绍
linux和unix都是当今鼎鼎大名的操作系统,可以说改变了这个世界,也是当今科技产业的重要基础.让我们回顾一下他们的发展史吧. 1.unix起源. 上世纪六十年代时,大部份计算机都是采用批处理的方式 ...
- 对Linux(Unix)的基础知识归纳
前言,不论是原生APP(Android&IOS),还是大型架构级基础环境(.NET&J2EE,或LAMP阵营等), 基本都不可避免的涉及到Linux(Unix),故还是觉得有必要把自己 ...
- Linux内核设计第五周——扒开系统调用三层皮(下)
Linux内核设计第五周 ——扒开系统调用三层皮(下) 一.知识点总结 1.给MenuOS增加新的命令的步骤 更新menu代码到最新版 test.c中main函数里,增加MenuConfig() 增加 ...
- Linux和UNIX监控
Linux和UNIX上的数据库监控工具包括监控CPU.内存.磁盘.网络.安全性和用户的监控工具.下面罗列了我们找到的有用工具及其简单描述. ps 显示系统上运行的进程列表 top ...
- 在Linux或者Unix下打开,每一行都会出多出^M这样的字符
Windows上写好的文件,在Linux或者Unix下打开,每一行都会出多出^M这样的字符,这是因为Windows与*nix的换行符不同所致,我们看看文件格式有什么不同. 在Linux下查看文件格式: ...
- 【笔记】Linux 和 Unix 作业控制
Linux 和 Unix 属于多任务的操作系统,也就是说一个系统在同一时间段内能运行多重任务(进程). 作业控制不只是能够停止/挂起(stop/suspend)正在执行的进程(命令),也可以继续/唤醒 ...
- linux 和unix 的区别
Linux与Unix的区别 某些PC机的Unix和Linux在实现方面相类似.几乎所有的商业Unix版本都基本支持同样的软件.程序设计环境和网络特性.然而,Linux和Unix的商业版本依然存在许多 ...
- Linux/hp unix/AIX日常巡检脚本(转)
以下为Linux/hp unix/AIX日常巡检脚本,大家可以参考着进行改写,用于自己的服务器. #!/usr/bin/ksh syserrdate=`date +"%m/%d"` ...
随机推荐
- 研读asp.net排课功能实现学习笔记
1.datatable.select 方法,返回的是一个datarow数组 DataRow[] drs = dtHBKC.Select("Subject ...
- virus.win32.parite.H病毒的查杀方法
virus.win32.parite.H病毒的查杀方法 昨天电脑中了virus.win32.parite.H病毒,搞了2个多小时最终搞定了.以下记录下我的解决方法. 第一步:下载Win32.Parit ...
- 数字证书, 数字签名, SSL(TLS) , SASL .
因为项目中要用到TLS + SASL 来做安全认证层. 所以看了一些网上的资料, 这里做一个总结. 1. 首先推荐几个文章: 数字证书: http://www.cnblogs.com/hyddd/ar ...
- UpdataData
MFC中有一个UpdataData函数,有二个参数:TRUE和FLASE,二个参数什么时候用, 开始的时候我也迷糊,后来才发现: UpdataData(TRUE):是把控件上的值刷新到变量中: Upd ...
- shodan
https://www.shodan.io/ from:http://www.exploit-db.com/wp-content/themes/exploit/docs/33859.pdf 0x00 ...
- [置顶] github简单使用
git的介绍可以看这里 http://zh.wikipedia.org/wiki/GitHub 安装和使用参考的这个 http://www.cnblogs.com/cocowool/arch ...
- dedecms 文章列表和频道列表同时调用
演示效果:http://www.mypf110.com/qcd/ <div class="changshi_wrap"> {dede:channelartlist ro ...
- A Game of Thrones(12) - Eddard
The summons(['sʌm(ə)nz]召唤:传票) came in the hour before the dawn, when the world was still and grey. A ...
- Qt笔记——MOC(莫克)
moc 代表 Meta-Object Compiler,"元对象编译器".Qt 程序在交由标准编译器编译之前,先要使用 moc 分析 C++ 源文件. 假设它发如今一个头文件里包括 ...
- 【Nginx】启动过程
从应用程序的启动过程中main功能开始跟踪. 解析命令行參数并保存到ngx_cycle_t结构体中,在ngx_process_options函数中将保存配置文件路径. 调用ngx_add_inheri ...