【APUE】文件I/O

1 文件描述符
    所有打开的文件都通过文件描述符引用,文件描述符是一个非负整数,本质是一个数组下标。
    当打开或创建一个文件的时候,内核向进程返回一个文件描述符。
    open,creat返回文件描述符来标识该文件,将其作为参数传递给write和read。
    UNIX系统shell使用文件描述符0与进程的标准输入相关联,1和标准输出相关联,2和标准错误输出相关联。:

2 open函数
    打开一个文件

  1. #include <fcntl.h>
  2.         int open(const char * pathname, int oflag, ...);
  3.         //若成功返回文件描述符,不成功返回-1
        pathname是打开或创建文件的名字。
        oflag说明次函数的多个选项:
                O_RDONLY        只读打开        0
                O_WRONLY        只写打开        1
                O_RDWR          读、写打开      2
        以上这三个参数必须且只能定义一个,下列常量是可选的
                O_APPEND        每次写入时追加到文件尾部
                O_CREAT         如果文件不存在,则创建。使用第三个参数来限制创建文件的权限。
                O_EXCL          如果指定了O_CREAT,则如果存在该文件,则会出错。
                O_TRUNC         如果只读或只写打开的文件存在,将其长度截短为0
                O_NOCTTY        如果pathname指定的是终端设备,则不将该设备分配作为此进程的控制终端。
                O_NONBLOCK      如果pathname指定的是一个FIFO,一个块特殊文件或一个字符特殊文件,则此选项为文本的本次打开操作和后续的I/O操作设置非阻塞模式。
        以下参数是Single UNIX Specification
                O_DSYNC         使每次write操作等待物理I/O完成,如果写操作不影响读取刚写入的数据,则不等待文件属性被更新
                O_RSYNC         使以文件描述符为参数的read等待,直到任何对文件同一部分进行的未决写操作都完成。
                O_SYNC          使每次write操作等待物理I/O完成。

3 creat函数
    创建一个文件
  

  1. #include <fnctl.h>
  2.     int creat(const char * pathname, mode_t mode);
  3.     //若成功则返回一个以只写打开的文件描述符,失败返回-1
    词函数等同于
            open(pathname, O_RDONLY | O_TRUNC | O_CREAT, mode);
    这个函数的缺点是返回一个以只写打开的文件描述符,建议使用open函数来创建文件:
            open(pathname, O_RDWR | O_CREAT | O_TRUNC, mode);

4 close函数

    关闭一个打开的文件

  1. #include <unistd.h>
  2.     int close(int filedes);
  3.     //若成功返回0,错误返回-1
    关闭一个文件的同时关闭在该进程中为文件加上的所有记录锁。
    *编程原则:谁打开谁关闭,谁申请谁释放

5 lseek函数
    每打开一个文件的时候,都有一个与其相关的“当前文件偏移量”,用以度量从文件开始处计算的文件字节数。
    按照系统默认情况,当文件打开时,除非指定O_APPEND选项,文件偏移量从0开始。
    可以调用lseek来显示的为打开文件设置其偏移量。
  

  1. #include <unistd.h>
  2.     off_t lseek(int filedes, off_t offset, int whence);
  3.     //若成功返回文件的偏移量,失败返回-1
    以下是whence属性
            SEEK_SET        将文件偏移量设置为距从文件开始处offset个字节
            SEEK_CUR        将文件偏移量设置为从当前处到offset个字节,offset可以为正/负
            SEEK_END        将文件偏移量设置为文件长度加offset
    可以用下面的方式打开文件的偏移量

  1.             off_t currpos;
  2.             currpos = lseek(fd, 0, SEEK_CUR);
6 read函数
    从打开的文件读取数据

  1. #include <unistd.h>
  2.     ssize_t read(int filedes, void * buf, size_t nbytes);
  3.     //若成功返回读到的字节数,若以到达文件结尾返回0,若出错返回-1
    ssize_t    带符号的整数
    size_t    不带符号的整数
    以下情况读到的字节数少于要求的字节数
        1.在读到要求字节数之前已经读到文件结尾
        2.当从终端设备文件读时
        3.从网络读时
        4.从管道或者FIFO读时
        5.从某些面向记录的设备读时(磁带)
        6.信号影响
    读操作从文件的当前偏移量开始,读取完毕该偏移量加上读取的实际字节数

7 write函数
    向打开的文件中写入数据

  1. #include <unistd.h>
  2.     ssize_t write(int filedes, const void * buf, size_t nbytes);
  3.     //若成功返回写入的字节数,若失败返回-1
    对于普通文件,write函数从文件的偏移量开始写,如果指定了O_APPEND选项,就从文件的结尾处开始写,在一次成功的写操作之后,该文件的偏移量加上实际写入的字节数

8 文件共享
    内核使用三种数据结构来表示打开的文件,它们之间的关系决定了在文件共享方面一个进程对另一个进程可能产生的影响。
    1.每个进程在进程表中都有一个记录项,记录项中包含一张打开文件描述符表,可将其视为一个矢量,每一个文件描述符占用一项,与每个文件描述符相关联的是:
        a.文件描述符标志
        b.指向一个文件表项的指针
    2.内核为每个打开文件维持一个文件表,每个文件表含:
        a.文件状态标志
        b.当前文件偏移量
        c.指向该文件v节点表项的指针
    3.每打开一个文件都有一个v节点结构。包含了文件类型和对此文件进行各种操作的函数的指针。

    如果有两个独立的进程各自打开了同一个文件,打开文件的每一个进程都将得到一个文件表项,但是对于一个给定的文件只有一个v节点表项。
    这种安排使得每个进程都有它自己的对该文件的当前偏移量。
    但是对于多个进程对同一文件进行写操作的时候就会产生不可预期的错误,所以要介绍原子操作。

9 原子操作
    为了避免多进程操作同一文件会产生覆盖的影响,有如下函数,该函数首先操作lseek,然后在进行读写操作

  1. #include <unistd.h>
  2.     ssize_t pread(int filedes, void * buf, size_t nbytes, off_t offset);
  3.     ssize_t pwrite(int filedes, const void * buf, size_t nbytes, off_t offset);
  4.     //其返回值和read,write类似
10 dup和dup2
    复制一个现存的文件描述符
    #include <unistd.h>
    int dup(int filedes);
    int dup(int filedes, int filedes2);
    //若正确,返回新的文件描述符,错误返回-1
    由dup返回的文件描述符一定是当前可用的最小的文件描述读
    dup2函数则用filedes2来指定新文件描述符,如果filedes2已经存在,则先将其关闭。若filedes2等于filedes则返回filedes2,而不关闭

11 sync, fsync, fdatasync函数
    保证了磁盘上实际文件系统与缓冲区高速缓存中内容的一致性
  

  1. #include <unistd.h>
  2.     int fsync(int filedes);
  3.     int fdatasync(int filedes);
  4.     //若成功返回0,失败返回-1
  5.     void sync(void);
    sync将所有修改过的块缓冲区排入写队列,然后就返回,不等待实际写磁盘操作结束。
    通常系统的守护进程update会定期调用sync,命令sync也是调用sync函数
    fsync对文件描述符filedes指定的单一文件起作用,并且等待实际写磁盘操作结束。同时也会同步更新文件的属性。
    fdtatsync和fsync类似,不过它值针对与数据部分。

12 fcntl函数
    可以改变以打开文件的属性
   

  1. #include <fcntl.h>
  2.     int fcntl(int filedes, int cmd, ...);
  3.     //若成功则返回值依赖于cmd,失败返回-1
    fcntl的五种功能cmd
    1.F_DUPFD            复制一个现有的文件描述符,与dup,dup2函数类似,返回一个文件描述符
    2.F_GETFD或F_SETFD        获得/设置文件描述符标记,返回文件描述符标记
    3.F_GETFL或F_SETFL        获得/设置文件状态标志,返回文件状态标志
        O_RDONLY    只读打开
        O_WRONLY    只写打开
        O_RDWR        读写打开
        O_APPEND    追加
        O_NONBLOCK    非阻塞模式
        O_SYNC        等待写完成(数据和属性)
        O_DSYNC        等待写完成(数据)
        O_RSYNC        同步读写
        O_FSYNC        等待写完成
        O_ASYNC        异步I/O

        前三个访问标志是互斥的,因此首先必须使用屏蔽字O_ACCMODE取得访问模式位,在比较

    4.F_GETOWN或F_SETOWN        获得/设置异步I/O所有权,返回一个正的进程ID或一个负的进程组ID
    5.F_GETLF、F_SETLK或F_SETLKW    获得/设置记录锁

13 ioctl函数

    I/O操作的杂物箱
 

  1. #include <unistd.h> // System V
  2.     #include <sys/ioctl.h> // BSD and linux
  3.     #include <stropts.h> // XSI STREAMS
  4.     int ioctl(int filedes, int request, ...);
  5.     //若出错返回-1,成功返回其他值


    在此原型中,我们表示的只是ioctl函数本身所要求的头文件。通常还需要另外的设备专用头文件<termios.h>

14 /dev/fd

    在较新的系统都提供名为/dev/fd的目录。打开/dev/fd/n等效于复制描述符n

阅读(241) | 评论(4) | 转发(0) |
给主人留下些什么吧!~~
16_avatar_small.jpg

lixiang22022012-05-19 21:11:24

星期五啦: 什么叫前三个访问标志是互斥的。。。.....
就是说 O_RDONLY  O_WRONLY   O_RDWR   这三个选项在一个文件中只能有一个值
00_avatar_small.jpg

星期五啦2012-05-17 21:04:52

什么叫前三个访问标志是互斥的。。。

12_avatar_small.jpg

小蝌蚪1232012-05-16 21:13:05

写的很好啊,浅显易懂~博主辛苦啦~5.gif

91_avatar_small.jpg

夏冰软件2012-05-16 16:46:06

写的不错,支持一下

评论热议
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章