UNIX文件I/O函数

来源:互联网 发布:淘宝1688批发 编辑:程序博客网 时间:2024/05/16 04:43

大多数UNIX都提供I/O函数,一般只需要这几个:open,read,write,lseek,close

不带缓存I/O:指的是每个read和write都调用内核中的一个系统调用,不带缓存的I/O函数不是ANSI C的一部分,但却是POSIX.1和XPG3的组成部分。

文件描述符:

对内核而言,所有打开的文件都由文件描述符来引用。在POSIX.1中,0,1,2分别代表常数STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO,它们都在《unistd.h》中定义,文件描述符的范围是0~OPEN_MAX,早期的UNIX一般支持20(OPEN_MAX=19)个,后来基本上扩展到64个。

open——打开或者创建文件

#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>//返回:成功时返回文件描述符,失败则返回-1int open(const char *pathname,int oflag,.../*,mode_t mode*/);

当open创建文件时,才使用第三个参数,用来说明文件的存取的许可权位。

pathname用于指定打开或者创建的文件的名字,oflag说明函数的选择项:

O_RDONLY 只读打开

O_WRONLY 只写打开

O_RDWR 读写打开

这三个选项应当只指定一个,下列是可选常数选项:

O_APPEND 每次写时都自动把写入位置置于文件尾端

O_CREAD 若此文件不存在,则创建文件,需要指定第三个参数

O_EXCL 如果指定了O_CREAT的同时文件又存在则出错,它可测试文件是否存在

O_TRUNC 如果文件存在,且是以只读或者只写打开,则将其长度截短为0

O_NOCTTY 如果pathname所指定的文件是终端设备,那么不能将此设备分配为进程的控制终端

O_NONBLOCK 如果pathname所指定的文件是FIFO,一个块特殊文件,一个字符特殊文件则此次打开文件操作和后续操作均设置为非阻塞

文件名或者文件路径截短

如果我们试图创建一个文件名或者路径名大于NAME_MAX的新文件,会发生什么呢?

早期的系统V版,允许使用文件名截短为NAME_MAX值,BSD系统则返回ENAMETOOLONG错误

在POSIX.1中,常数_POSIX_NO_TRUNC决定了是否要截短文件名或者路径名,否则返回错误

creat——创建一个新文件

#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>//返回:成功则返回只写打开文件的描述符,出错则返回-1int creat(const char *pathname,mode_t mode);

此函数等价于:

open( pathname , O_WRONLY | O_CREAT | O_TRUNC , mode );

如今已经不需要creat函数了,因为本身creat函数受制于只写打开文件,调用creat函数并读取文件,必须经过如下序列函数调用:creat——>close——>open——>read

close——关闭一个打开的文件

#incluede <unistd.h>//返回:成功为0,出错为-1int close(int filedes);

调用close关闭一个文件时,也会释放进程加载在该文件上的所有记录锁。另外,当进程终止时,它多打开的文件都由内核自动关闭。
lseek——定位文件

#include <sys/types.h>#include <unistd.h>//返回:成功则返回新的文件位移,出错则为-1off_t lseek(int filedes,off_t offset,int whence);

每一个打开的文件都有一个与其关联的“文件当前位移量”,通常它为一个非负数,用以度量从文件开始处计算的字节数,而文件的读和写都从当前文件位移量处开始,并使位移量增加所读和所写的字节数,按系统默认,当打开一个文件时,除非指定O_APPEND选项,位移量均为0

对whence参数

SEEK_SET 文件开始处

SEEK_CUR 文件当前处

SEEK_END 文件末尾处

为此,可以用下列方式获取一个打开的文件的当前位移量

off_t curpos=lseek(fileded,0L,SEEK_CUR);

同时这中方法也可以用来测试所涉及的文件是否支持设置位移量,比如当文件描述符所指定的文件是一个FIFO,一个管道,则lseek返回-1,并将errno设置为EPIPE。

通常,文件位移量为非负值,但有部分特殊设备支持文件位移量为负数,所以对lseek的返回值需慎重,不要检测其是否小于 0,而应检测是否等于 -1。

lseek将文件偏移量记录在内核中,这个操作并不会引起I/O操作,这个具体将在文件的数据结构中解释。

文件位移量可以大于文件长度,在这种情况下会延长文件长度,并在中间未写入部分形成空洞,空洞部分都置为0。

read——读文件

#include <unistd.h>//返回:读到的字节数,若已经到文件末尾则返回0,出错则返回-1int read(int filedes,void *buff,size_t nbytes);

有多种情况使读到的字节数少于要求读的字节数

a.读普通文件,在读到要求的字节数之前就达到文件末尾了,返回0

b.当从终端中读取时,通常一次读取一行

c.当从网络读取时,因为网络的缓冲机制,可能造成读取的字节数少于要求的字节数

d.某些面向记录的设备,比如磁带,一次最多读取一个记录

write——写文件

#include <unistd.h>//返回:成功时返回写入字节数,出错返回-1int write(int filedes,void *buff,size_t nbytes);

write可能因为返回写入的字节数少于要求的字节数而出错,常见原因是:磁盘已满或者文件超出一个给定进程的文件长度限制。

实例:

1.标准输入复制到标准输出

//把标准输入复制到标准输出#include <unistd.h>int main(){//8192这个块大小值在很多情况下可以提高I/O效率char buff[8192];int n;while( (n=read(STDIN_FILENO,buff,8192)) >0){if( write(STDOUT_FILENO,buff,n)!=n){perror("Write error .\n");}} return 0;}

2.创建一个有空洞的文件

//创建一个空洞文件#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>int main(){char filename[]="file.hole";int fd;if( (fd=open(filename,O_RDWR|O_CREAT,777)) <0){perror("File create error .");}//the offset now=0if( write(fd,"abcdefghi",10) !=10){perror("File write error ");}//the offset now=10if( lseek(fd,10L,SEEK_CUR) ==-1){perror("File seek error .");}//the offset now=20if( write(fd,"ABCDEFGHI",10) !=10){perror("File write error ");}//the offset now=30return 0;}


这篇只是介绍了几个非缓冲文件I/O基本的函数,不属于ANSI C的组成部分。

加油。

原创粉丝点击