[APUE]第三章文件I/O

来源:互联网 发布:sql 选取时间段 编辑:程序博客网 时间:2024/06/05 12:44

Unix系统中大多数文件I/O只需用到五个函数:open、read、write、lseek、close。本章介绍的I/O是不带缓冲的,即:每个read和write都调用内核中的一个系统调用。它们不是ISO C的组成部分。
对于内核而言,所有打开的文件都通过文件描述符引用;
当打开或创建文件时,内核向进程返回一个文件描述符;
读写文件时,文件描述符将作为read和write的参数。
在 unistd.h中定义三个标准的文件描述符:

STDIN_FILENO (0)  标准输入STDOUT_FILENO (1) 标准输出STDERR_FILENO (2) 标准出错输出

文件描述符的变化范围是0~OPEN_MAX,早期的UNIX系统实现采用的上限是19,现在 大多数系统的OPEN_MAX为63。

open和openat函数

int open(const char *path, int oflag, … ); //打开或者创建一个文件
int openat(int fd,const char *path, int oflag, … ); //打开或者创建一个文件
最后一个参数为…的形式为可变参数,对于open函数只有在创建新文件时才使用最后这个参数。
由open和openat函数返回的文件描述符一定是最小的未用描述符数值。

lseek()函数

off_t lseek(int fildes, off_t offset, int whence); //为打开的文件设置偏移量
whence可选:SEEK_SET, SEEK_CUR, SEEK_END
SEEK_SET:将该文件的偏移量设置为距文件开始处offset个字节。
SEEK_CUR:将该文件的偏移量设置为其当前值加offset。
SEEK_END:将该文件的偏移量设置为文件长度加offset,offset可正可负。
如果文件描述符指向的是一个管道 FIFO 网络套接字,则lseek返回-1,并将errno设置为ESPIPE.
通常偏移量是一个非负整数,但是对有些设备来说可以是负的,所以为安全起见,对返回值不要测试它是否小于0,而要测试它是否等于-1。

当文件偏移量大于文件的长度时,对文件的下一次写将加长该文件,并在文件中构成一个空洞(没有写过的字节被读为0),文件的空洞并不占用磁盘的存储区。

 #include "apue.h"intmain(void){    if (lseek(STDIN_FILENO, 0, SEEK_CUR) == -1)        printf("cannot seek\n");    else        printf("seek OK\n");    exit(0);}

由于文件描述符指向管道 FIFO 网络套接字时,lseek返-1,所以书中第二个示例:
cat < /etc/passwd | a.out会打印cannot seek
关于管道:
命令从标准输入到读取数据,并将数据发送到标准输出的能力,是使用了名为管道的shell特性。使用|可以把一个命令的标准输出传送到一个命令的标准输入中:
command1 | command2
上面例子中其实等价于:
cat /etc/passwd | a.out
使用重定向符号”<”,我们把标准输入的源从键盘变为文件/etc/passwd文件。把一个文件作为标准输入的源文件,cat 输出文件内容,传递给a.out

#include "apue.h"#include <fcntl.h>char    buf1[] = "abcdefghij";char    buf2[] = "ABCDEFGHIJ";intmain(void){    int     fd;    if ((fd = creat("file.hole", FILE_MODE)) < 0)        err_sys("creat error");    if (write(fd, buf1, 10) != 10)        err_sys("buf1 write error");    /* offset now = 10 */    if (lseek(fd, 16384, SEEK_SET) == -1)        err_sys("lseek error");    /* offset now = 16384 */    if (write(fd, buf2, 10) != 10)        err_sys("buf2 write error");    /* offset now = 16394 */    exit(0);}


中文版第三版这里有个错误如下:

勘误二

p55页 中文版中“从中可以看到,文件中间的30个未写入字节都被读成0,每一行开始的一个7位数是以8进制形式表示的字节偏移量。”
实际上英文原版中的内容如下:

#include "apue.h"#include <fcntl.h>intmain(int argc, char *argv[]){    int     val;    if (argc != 2)        err_quit("usage: a.out <descriptor#>");    if ((val = fcntl(atoi(argv[1]), F_GETFL, 0)) < 0)        err_sys("fcntl error for fd %d", atoi(argv[1]));    switch (val & O_ACCMODE) {    case O_RDONLY:        printf("read only");        break;    case O_WRONLY:        printf("write only");        break;    case O_RDWR:        printf("read write");        break;    default:        err_dump("unknown access mode");    }    if (val & O_APPEND)        printf(", append");    if (val & O_NONBLOCK)        printf(", nonblocking");    if (val & O_SYNC)        printf(", synchronous writes");#if !defined(_POSIX_C_SOURCE) && defined(O_FSYNC) && (O_FSYNC != O_SYNC)    if (val & O_FSYNC)        printf(", synchronous writes");#endif    putchar('\n');    exit(0);}


关于重定向的语法 >>是追加到文件末尾,5<>temp.foo表示在文件描述符5上打开文件temp.foo以供读 写。

小结

本章说明了UNIX系统提供的基本I/O函数。因为read和write都在内核执行,所以称这些函数为不带缓冲的I/O函数。在只使用read和write情况下,我们观察了不同的I/O长度对读文件所需时间的影响。我们也观察了许多将已写入的数据冲洗到磁盘上的方法,以及他们对应用程序性能的影响。

原创粉丝点击