• Chapter 3 文件I/O


    1.文件描述符

    文件描述符是一个非负整数,当打开一个现有文件或创建一个新文件时候,内核向进程返回一个文件描述符。Unix系统shell使用文件描述符0与进程的标准输入相关联,文件描述符1与进程的标准输出相关联,文件描述符2与进程的标准出错相关联,在POSIX标准中,幻数0、1、2应当替换为符号常量STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO,另外文件描述符变化范围:0~OPEN_MAX,现在很多系统将OPEN_MAX置为63

    2.open函数

    调要open函数可以打开或创建一个文件。

    函数原型

    #include <fcnt1.h>
    int open(const char *pathname,int oflag,/*mode_t made*/);

          pathname是需要打开的文件;

          oflag参数用来说明此函数的多个选项。用 O_RDONLY(只读),O_WRONLY(只写),O_REWR(读写)。这三个常量必须指定,有且只能指定一个,并且和下列多个常量进行或运算构成:

          O_APPEND        每次写时都追加到文件的尾端

          O_CREAT          若文件不存在则创建它,需要第三个参数为指定文件的访问权限

          O_EXCL            若同时指定O_CREAT,而文件存在则会出错,用此则可以测试文件是否存在,若不存在则创建这个文件

          O_TRUNC         如果此文件不存在,而且为只写或读写成功打开,则将其长度截短为0

          O_NOCTTY        若pathname指的是终端设备,则不将该设备分配为此进程的控制端

          O_NONBLOCK    非阻塞模式

          这些常量是可选择的

    3.create函数

    函数原型

    #include <fcnt1.h>
    int create(const char *pathname,mode_t mode);

    此函数等效于

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

    4.close函数

    函数原型

    #include<fcnt1.h>
    int close (int filedes);  //返回值若成功返回0不成功返回-1


     

    5.lseek函数

    可以用lseek显式地为一个打开的文件设置其偏移量。

    函数原型

    #include<unistd.h>
    off_t lseek(int fileds,off_t offset,int whence);
    //若成功则返回新的文件偏移量,若出错则返回-1

    参数whence可以置为下值

    SEEK_SET,则将该文件的偏移量设置为距文件开始出offset个字节

    SEEK_CUR,则将该文件的偏移量设置为其当前值加offset,offset可正可负

    SEEK_END,则将该文件的偏移量设置为文件长度加offset,offset可正可负

    若lseek成功执行,则返回新的文件偏移量,为此可以用下列方式确定打开文件的当前偏移量

    off_t currpos;
    currpos = lseek(fd,0,SEEK_CUR);

    这种方法也可以用来确定所涉及的文件是否可以设置偏移量,如果文件描述符引用的是一个管道、FIFO进而网络套接字,则lseek返回-1,并将errorn设置为ESPIPE。

    注意:

    1).lseek仅将当前的文件偏移量记录在内核中,它并不引起任何I/O操作

    2).文件偏移量可以大于文件的当前长度,在这种情况下,对该文件下一次的写将加长该文件,并在文件构成一个空洞,这一点是允许的。位于文件中但没有写过的字节都被设为 0

    3).文件中的空洞并不要求在磁盘上占用存储区。

    6.read函数

    从打开的文件中读数据到buf

    #include <unistd.h>
    ssize_t read(int filedes,void *buf,size_t nbytes);

    返回值:若成功则返回读到的字节数,若已到文件结尾则返回0,若出错返回-1;

    7.write函数

    调用write函数向打开的文件写数据

    #include <unistd.h>
    ssize_t write(int filedes,const void *buf,size_t nbytes);

    返回值:若成功则返回字节数,若出错返回-1

    注:write出错的一个常见原因是:磁盘已写满,或者超过了一个给定进程的文件长度限制

    8.dup和dup2函数

    这两个函数都用来复制一个现存的文件描述符

    #include <unistd.h>
     
    int dup(int filedes);    
    int dup2(int filedes,int filedes2);   //filedes2参数指定新描述符的数值。如果filedes2已经打开,则先关闭。

    返回值:若成功返回新的文件描述符,若出错则返回-1

    调用

    dup(filedes);

    等效于

    fcntl(filedes, F_DUPFD, 0);

    而调用

    dup2(filedes, filedes2);

    等效于

    close(filedes2);
    fcntl(filedes, F_DUPFD, filedes2);


    区别

    1).dup2是一个原子操作,而close及fcntl则包括两个函数调用,有可能在close和fcntl之间插入执行信号捕获函数

    2).dup2和fcntl有某些不同errorno

    9.sync,fsync ,fdatasync函数

    为了解决延迟写的问题,保证磁盘上实际文件系统和缓冲区高速缓存中内容的一致性。

      #include <unistd.h>
     
    int fsync(int filedes);           // 只对由文件描述符filedes指定的单一文件其作用,并且等待写磁盘操作结束
     
    int fdatesync(int filedes);       //功能和fsync差不多,但它还同步更新文件的属性
     
    void sync(void);                  //将所有修改过的快缓冲区排入写队列,然后返回,它并不等待实际写磁盘操作结束

    10.fcntl函数

    可以改变已打开的文件性质

    #include <fcnt1.h>
     
    int fcnt1(int filedes,int cmd, /* int arg *);

    第三个参数总是一个整数,与上面所示函数原型中的注释部分相对应。但是在作为记录锁用时,第三个参数则是指向一个结构的指针。

    fcntl函数有5种功能:

    1).复制一个现有的描述符(cmd=F_DUPFD).
    2).获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD).
    3).获得/设置文件状态标记(cmd=F_GETFL或F_SETFL).
    4).获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN).
    5).获得/设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW).

    11.ioctl函数

    ioctl函数是I/O操作的杂物箱,完成其他函数都无法完成的操作

    #include <unistd.h>          /*System V*/
    #include <sys/ioctl.h>       /*BSD and Linux*/
    #include <stropts.h>         /*XSI STREAMS*/
    
    int ioctl(int filedes, int request, . . .);

    详见APUE第十八章

    12./dev/fd

       比较新的unix/linux系统都提供名为/dev/fd的目录,其中有文件0、1、2等文件,打开这些文件,相当于复制这些文件描述符

    例如:

    fd=open("/dev/fd/0",mode);

    等价于

    fd=dup(0);

    文件描述符fd和0将共享一个文件表记录项。

    13.文件共享

    文件共享是指不同进程间打开文件的共享。内核通过三种数据结构来表示打开的文件,

    1).每个进程有个进程表项,表中是打开文件的描述符向量。每个向量包含了文件描述符标记和一个指向文件表项的指针;

    2).内核为所有打开的文件维护一个文件表,每个文件表项包括了a,文件状态标记,如读、写、添加、非阻塞等b,当前的文件偏移量c,指向文件v-node表项的指针;

    3).每个打开文件或设备都有一个v-node结构   ,包含文件类型和指向操作文件的函数的指针。

    当两个以上独立进程打开同一个文件实现文件共享时,内核维护不同的文件表项,就是两个以上进程表项中的文件表项指针指向不同的文件表项,而不同的文件表项中的v-node指针指向同一个v-node而实现文件共享。由于每个进程有自己的打开文件表项,所以有自己的文件打开状态以及文件偏移量。

    需要注意的是Linux没有将相关数据分为i节点和v节点,而是采用了一个独立于文件系统的i节点(通用i-node结构)和一个依赖于文件系统的i节点

  • 相关阅读:
    手脱ASPack v2.12变形壳2
    手脱nSPack 2.1
    WCF分布式开发步步为赢(1):WCF分布式框架基础概念
    一个经典例子让你彻彻底底理解java回调机制
    C#三层架构详细解剖
    eclipse快捷键及各种设置
    设计模式总结
    程序猿也爱学英语(上)
    关于PDA、GPS等动态资源的几种GIS解决方案
    通过VS2010性能分析来查找代码中那些地方最损耗资源
  • 原文地址:https://www.cnblogs.com/biyeymyhjob/p/2618854.html
Copyright © 2020-2023  润新知