首先我们来理解一个概念:不带缓冲的I/O,我们说Unix下面的read和write是不带缓冲的是指:
(1)每个read和write都调用内核中的一个系统调用(进程不提供缓冲)
(2)系统内核为磁盘的读写提供了缓冲块,当我们write时,直接调用系统调用,但是数据写到了缓冲块,缓冲块满了才会写入文件(内核提供了缓冲)
那么带缓冲的I/O简单的来说,就是指提供了一个缓冲区,内核也提供了一个缓冲区。比如我们的c标准库,第一次读写的时候,标准库从内存分配一个缓冲区,当这个缓冲区满了或者刷新缓冲区时,把数据送往内核的块缓冲区,再根据块缓冲区的情况读取或写入磁盘,那么标准库为什么要设定一个缓冲区呢,就是因为直接从硬盘I/O效率很低,所以提供了一个缓冲区
接下来我们总结一下Unix内核为我们提供的文件I/O的函数:
(其实总结加深记忆,不记得直接man么@_@)
1、 read
#include <unistd.h>
ssize_t read(int filedes, void *buf, size_t nbytes)
有多种情况会出现读到的字节数小于要求的字节数:
读取普通文件,在读到要求的字节数之前已达到文件尾端
从终端设备读取时,一次最多只能读取一行
从网络读取时,网络的缓冲机制可能返回小于所要求读取字节数
2、 write
#include <unistd.h>
ssize_t write(int fieldes,const void*buf, size_t nbutes)
write出错可能是因为磁盘已满
3、 open
#include<fcntl.h>
int open(const char*pathname, int flags, mode_t mode);
O_RDONLY 只读打开
O_WRONLY 只写打开
O_RDWR 可读可写打开
上面三个是必选且只能选一个,下面的的可选,与上面的取或
O_APPEND 表示追加。如果文件已有内容,这次打开文件所写的数据附加到文件的末尾而不覆盖原来的内容。
O_CREAT 若此文件不存在则创建它。使用此选项时需要提供第三个参数mode ,表示该文件的访问权限。
O_EXCL 如果同时指定了O_CREAT,并且文件已存在,则出错返回。
O_TRUNC 如果文件已存在,并且以只写或可读可写方式打开,则将其长度截度(Truncate)为0字节。
O_NONBLOCK 如果指向的是一个FIFO,一个块特殊文件或一个字符特殊文件,以O_NONBLOCK 方式打开可以做非阻塞I/O(Nonblock I/O)
早期的文件描述符最多只有20个,所以有这个close函数,关闭已打开的文件描述符
#include <unistd.h>
Int close(int filedes)
下面以一个简单的cp程序来总结着这几个函数
#include <stdio.h>
#include <fcntl.h>
#define PERMS 0666
int main(int argc, char *argv[])
{
int f1, f2, n;
charbuf[BUFSIZE];
if(argc!=3)
printf(“usage:cpfrom to”);
if((f1 = open(argv[1], O_RDONLY, 0))== -1)
printf(“cp:can’topen %s”,argv[1]);
if((f2 = open(argv[2], O_WRONLY|O_CREAT|O_APPEND, PERMS))== -1)
printf(“cp:can’topen %s”,argv[1]);
while((n = read(f1, buf, BUFSIZE))> 0)
if(write(f2,buf, n) != n)
printf(“cp:writeerror on file %s”,argv[2])
return 0;
}