您的位置:首页 > Web前端

unix环境高级编程之unbuffered io

2011-02-21 21:42 316 查看
 

五个文件io函数,open,read,write,lseek,close;

不带缓冲的io是指每个read,write函数都调用内核中的一个系统调用。它在多进程间共享资源,原子操作就变得很重要。

 

文件描述符:

对于内核而言,所有打开的文件都是通过文件描述符引用。他是一个费负整数,当打开或者创建一个文件,内核向进程返回一个文件描述符。

当读或者写一个文件时,使用open或creat返回的文件描述符标识该文件,将其作为参数传给read或write。

0----标准输入  STDIN_FILENO

1-----标准输出 STDOUT_FILENO

2-----标准错误输出 STDERR_FILENO (定义在unistd.h中)

 

文件描述符限制在0-OPEN_MAX间

 

open函数

#include<fcntl.h>

int open(const char *pathname, int flag, /* mod_t mode */)

成功返回文件描述符,失败返回-1

flag有以下几种,可以用或运算构成flag参数

O_RDONLY 只读 0 

O_WRONLY  只写 1 

O_RDWR  读写 2

 

这三个常量中必须指定一个且只能指定一个,则下列常量是可选的。

O_APPEND 每次写追加到末尾

O_CREAT 若此文件不存在则创建它,使用此选项时需要指定第三个参数设置文件的访问权限

O_EXCL 如果同时指定了O_CREAT,而文件存在,则会报错。可用来测试一个文件是否存在,如果不存在则创建之,使测试和创建成为一个原子操作。
O_TRUNC 如果此文件存在,而且为只写或读写成功打开,则将长度截短为0
O_NOCTTY 如果pathname指的是终端设备,则不将此设备分配作为此进程的控制终端。
O_NOBLOCK 如果pahtname指的是一个FIFO,一个特殊块,或一个字符特殊文件,则此选项为文件的本次打开操作和后续的io操作设置非阻塞模式.
下面这三个操作是可选的
O_DSYNC 使每次write等待物理io操作完成,但是如果写操作并不影响读取到刚写入的数据,则不等待文件属性被更新。
O_RSYNC 使每一个以文件描述符作为参数的read操作等待,直到任何对文件同一部分进行的未决写操作都完成
O_SYNC 使每次写都等到物理io完成,包括有write操作引起的文件属性更新所需要的io。
creat函数
#include<fcntl.h>
int creat(const char *pathname, mod_t mod)
若成功则返回只写打开的文件描述符,否则返回-1
等价于
open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mod)
由于unix早期版本中,open函数第二个参数只能是0,1或2,没有办法打开一个不存在的文件,因此需要creat创建一个新文件,现在open提供了O_CREAT, O_TRUNC,于是也不需要creat函数
close 函数
关闭一个打开的文件
#include <unistd.h>
int  close(int filedes)
成功返回0,失败返回-1

lseek函数
没打开一个文件都会有一个与其相关联的“当前文件偏移量”,通常是一个非负整数,读写都是从当前文件偏移量开始,并使偏移量增加所读写的字节数。打开一个文件如果没有指定O_APPEND,则默认偏移量为0,这也是为什么写会覆盖原先的数据。
#include<unistd.h>
off_t lseek(int filedes, off_t offset, int whence);
成功返回新的文件偏移量,失败返回-1
对offset的解释与参数whence有关
若whence是SEEK_SET,则将偏移量设置为据文件开始处offset字节。
若whence是SEEK_CUR,  则将偏移量设置为据当前值加上offset,offset可为正或负。
若whence是SEEK_END, 则将文件偏移量设置为文件长度加offset,offset可正可负。

若lseek成功则放回新的文件偏移量,失败返回-1
可用lseek(filedes, 0, SEEK_CUR)来测试文件是否可以设置偏移量。如果文件描述符引用的是FIFO,网络套接字,管道,则lseek返回-1,并将errno设置为ESPIPE
lseek便宜了记录在内核中,并不引起io操作,然后该偏移量用于下一个读或写操作。
偏移量大于当前文件长度将会引起文件空洞,文件空洞并不需要占用存储空间。
read函数
#include<unistd.h>
ssize_t read(int filedes, void *buf, size_t nbytes);
若成功则返回读到的字节数,读到文件尾则返回0,错误返回 -1
write函数
#include <unistd.h>
ssize_t write(int filedes, const void *buf, size_t nbytes);
返回值与nbytes相同,否则表示出错。通常是磁盘已满,或者是超过一个给定进程的文件长度。
I/O效率

当bufsize为1024时io效率最好,可由试验得到。

 

文件共享

unix支持在不同的进程间共享打开的文件。

内核使用三种数据结构表示打开的文件。

1。每个进程在进程表中都有一个记录项。

2。内核为打开的所有文件维护一张文件表。

3。每个打开文件或设备都有一个v节点结构。

 

原子性操作

pread,pwrite

 

dup和dup2函数

用来复制一个现存的文件描述符

dup(filedes);等效于 fcntl(filedes, F_DUPFD, 0);

而调用dup2(filedes, filedes2)等效于close(filedes2); fcntl(filedes, FDUPFD, filedes2);

后一种情况并不完全等于close加上fcntl操作,因为dup2是原子操作

 

sync,fsync,fdatasync函数

传统unix实现在内核中并没有高速缓冲去,高速缓存,或页面高速缓存,大多数io都是通过缓冲进行。

#include<unistd.h>

int fsync(int filedes);

int fdatasync(int filedes);

成功返回0, 错误返回-1

void sync(void);

sync 只将所有修改过的块缓冲区排入写入队列,然后就返回,并不等待实际写磁盘操作结束。

通常称为update的系统守护程序会周期性的调用sync函数。这就定期的冲洗内核的块缓冲区。

 

fsync函数只对由文件描述符filedes指定的单一文件起作用,并且等待写磁盘操作结束。可用于数据库类的程序,可以保证修改过的块立即写入到磁盘上。

fdatasync类似于fsync,但它只影响文件的数据部分。而数据外,fsync还会更新文件的属性。

 

fcntl函数

改变已经打开文件的性质。

#include <fcntl.h>

int fcntl(int filedes, int cmd, .../* int arg */);

返回值:若成功则依赖于cmd,出错返回-1

fcntl函数有五种功能:

1。复制一个现有的描述符 cmd=F_DUPFD

2。获得/设置文件描述符标记 cmd=F_GETFD/F_SETFD

3。获得设置文件状态标志 cmd=F_GETFL/F_SETFL

4。获得设置异步io所有权 cmd=F_GETOWN/F_SETOWN

5。获得/设置记录锁 cmd=F_GETLK, F_SETLK或者F_SETLKW

 

ioctl函数

ioctl函数是io操作的杂物箱,不能用本章中的其他函数表示的io函数都能用ioctl表示。

终端io是ioctl的最大 使用方面

#include <unistd.h>

#include <sys/ioctl.h>

#include <stropts.h>

int ioctl(int filedes,  int request, ...);

出错返回-1,成功返回其他值。

 

/dev/fd

较新的系统度提供了/dev/fd目录,其目录项是名为0,1,2等文件,打开/dev/fd/n等效于复制描述符n,(假定描述符n是打开的);

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  unix 编程 io cmd 磁盘 终端