Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3521906
  • 博文数量: 534
  • 博客积分: 11595
  • 博客等级: 上将
  • 技术积分: 5785
  • 用 户 组: 普通用户
  • 注册时间: 2006-12-22 17:00
文章分类

全部博文(534)

文章存档

2015年(4)

2014年(27)

2013年(15)

2012年(38)

2011年(36)

2010年(85)

2009年(63)

2008年(142)

2007年(124)

分类: C/C++

2010-01-28 20:06:00

在APUE第三节——File I/O 中,主要描述的是一系列的 I/O 函数,通过一些函数来进行文件的一些操作。

这些操作基本上用下面这几个系统函数:open, read, write, lseek, close。在这一章中所有的系统函数

都属于“非缓冲文件”(unbuffered I/O)。开头第2段文字有这样一句话来描述  "unbuffered" : The term

unbuffered means that each read and write invokes a system call in the kernel. 也就

是说这些函数都是直接调用内核中的系统函数,它完全没有经过“缓冲区”,直接调用了。所以,这样不经过

“缓冲区”速度就肯定比经过“缓冲区”快了。这篇学习笔记将对“缓冲文件系统”和“非缓冲文件系统”作一个

比较,当然,主要还是放在“非缓冲文件系统”方面来描述。

一、缓冲文件系统简要描述:

    第一段简单说到了, “缓冲文件系统”的文件操作要经过“缓冲区”,那么具体如何操作呢?比如说最常用的

read 和 write。首先操作系统会在内存区域开辟一个缓冲区,顾名思义缓冲区就是用于缓冲的。如果要执行

read操作,那么先从磁盘那里把数据内容读入了缓冲区,然后等到把缓冲区装满之后,CPU再从缓冲区把数据

读入特定的变量。如果是写操作,刚好是反过来了,CPU先把数据一个个写进缓冲区里面,等到写满之后就把

缓冲区刚刚写进的数据写入到文件里面了。

    ANSI C 中函数库支持“缓冲区文件系统”, 所以文件操作函数像 fopen, fclose, fread, fwrite等都是

属于缓冲I/O。这里不多说这些函数了。

二、非缓冲文件系统描述:

    在ANSI C 中函数库支持“缓冲区文件系统”,但不支持“非缓冲文件系统”,“非缓冲文件系统”是POSIX.1

和  UNIX specification 的一部分。

    前面说到了,非缓冲I/O是系统直接的输入和输出,它不经过“缓冲区”,所以从速度和效率方面来说就显得

快一些了。下面对几个基本的unbuffered I/O 函数的功能通过配合代码描述一下。


1. int open(const char *pathname, int flags);

   int open(const char *pathname, int flags, mode_t mode);    


    man手册上提供的函数原型。pathname 是路径名,是文件打开或者新建的文件名字。参数 flags 是选择

的描述符。man手册上有句话这样描述flags:The  parameter  flags  must  include one of the

following accessmodes:O_RDONLY, O_WRONLY, or O_RDWR. These request opening  the  file 

read-only, write-only,  or  read/write, respectively.还有通过“位与”的模式来描述flags的,man手册上

都写得很具体了。比较上面两个open原型,发现第2个函数原型多了一个参数mode_t mode.有什么区别? 

The argument mode specifies the permissions to use in case a  new  file is created. 所有只有当

是新建文件的时候,第3个参数才有它的作用,在手册上也一几个你列举了这个参数的一些值了。下面这样调用

open 就是等价于新建了一个文件:


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



2. ssize_t read(int fd, void *buf, size_t count);

    ssize_t : functions that return a count of bytes(signed).


注意到第1个参数fd, 这是文件的描述符。对于内核来说,所有的文件都用文件描述符来描述。read函数作用:

从文件描述符 fd 中读 count 个字节 进入 buf区。函数执行成功返回读入的字节数,失败的话返回 -1, 并

对 errno 赋予相应的值。


3.ssize_t write(int fd, const void *buf, size_t count);


和  read 函数相反,从 buf 里写count个字节进入文件描述符fd里面。


4.off_t lseek(int fildes, off_t offset, int whence);


off_t : file sizes and offsets(signed);

lseek是随机访问文件函数。这个函数非常重要。因为每次对文件进行读写操作的位置总是在前一次操作之后。

这样有时候要访问文件的其他位置就麻烦了,就得依靠这个函数了。

    fildes:文件描述符;

    offset:访问的文件的位置

    whence:值可以是0,1,2;分别表示从文件开始、从文件当前位置、从文件结束位置;

    返回值:成功就返回新的文件位置,失败返回-1。


5. int close(int fd);


close 很简单,关闭一个文件描述符,这样就这个文件内容就不会被无意修改和使用了。

返回0表示执行成功,返回-1表示执行失败。


6. int creat(const char *pathname, mode_t mode);


用于创建一个新的文件。参数就不说了,参照open函数。 creat函数返回一个新文件描述符。

三、实例简单分析:

实例1:下面的程序是来自Figure 3.2,利用几个基本函数构造而成,非常简单,简单的分析都在注释里面

了;


#include "apue.h"
#include <fcntl.h>

char buf1[] = "abcdefghij";
char buf2[] = "ABCDEFGHIJ";

int main(void)
{
    int        fd;    

    /*offset is 0 when the file is created.*/
    if ((fd = creat("file.hole", FILE_MODE)) < 0)
        err_sys("creat error!");

    
/*offset is 10 after calling the write function.
    * write 10 bytes form buf1 to fd*/

    if (write(fd, buf1, 10) != 10)
        err_sys("buf1 write error!");
    
    /*offset is 16384 after calling the lseek function*/
    if (lseek(fd, 16384, SEEK_SET) == -1)
        err_sys("lseek error!");    

    /*offset is 16394 because we write 10 bytes form buf2*/
    if (write(fd, buf2, 10) != 10)
        err_sys("write error!");

    exit (0);
}


实例2 :read & write 的配合


#include "apue.h"

int main(void)
{
    int        n;
    char     buf[4096];

    /*read from the stdin file and write to stdout*/
    while ((n = read(STDIN_FILENO, buf, 4096)) > 0)
        if (write(STDOUT_FILENO, buf, n) != n)
            err_sys("write error");

    if (n < 0)
        err_sys("read error");

    exit (0);
}

 
阅读(1217) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~