您的位置:首页 > 产品设计 > UI/UE

[APUE]第三章文件I/O

2017-11-26 01:03 127 查看
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"
int
main(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";

int
main(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>

int
main(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长度对读文件所需时间的影响。我们也观察了许多将已写入的数据冲洗到磁盘上的方法,以及他们对应用程序性能的影响。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  apue 文件IO