APUE:文件IO

文件IO

open函数

#include 
#include 
#include 
int open(const char * pathname , int oflag,.../*, mode_t mode * / ) ;
返回:若成功为文件描述符,若出错为- 1

pathname是要打开或创建的文件的名字。oflag参数可用来说明此函数的多个选择项。用下
列一个或多个常数进行或运算构成oflag参数(这些常数定义在头文件中):

  • O_RDONLY 只读打开。
  • O_WRONLY 只写打开。
  • O_RDWR 读、写打开。
  • O_APPEND 每次写时都加到文件的尾端。
  • O_CREAT 若此文件不存在则创建它。
  • O_EXCL 如果同时指定了O_CREAT,而文件已经存在,则出错。若不存在则创建为原子操作。
  • O_TRUNC 如果此文件存在,而且为只读或只写成功打开,则将其长度截短为 0。
  • O_NOCTTY 如果pathname指的是终端设备,则不将此设备分配作为此进程的控制终端。
  • O_NONBLOCK 如果pathname指的是一个FIFO、一个块特殊文件或一个字符特殊文件,则此选择项为此文件的本次打开操作和后续的 I / O操作设置非阻塞方式。
  • O_SYNC 使每次write都等到物理I/O操作完成。

close函数

#include 
int close (int filedes);
返回:若成功为0,若出错为-1

关闭一个文件时也释放该进程加在该文件上的所有记录锁。
当一个进程终止时,它所有的打开文件都由内核自动关闭。很多程序都使用这一功能而不
显式地用close关闭打开的文件。

lseek函数

文件偏移量,按系统默认,当打开一个文件时,除非指定O_APPEND选择项,否则该位移量被设置为0。

#include 
#include 
off_t lseek(int filedes, off_t offset, int whence) ;
返回:若成功为新的文件位移,若出错为- 1
  • 若whence是SEEK_SET,则将该文件的位移量设置为距文件开始处offset 个字节。
  • 若whence是SEEK_CUR,则将该文件的位移量设置为其当前值加offset, offset可为正或负。
  • 若whence是SEEK_END,则将该文件的位移量设置为文件长度加offset, offset可为正或负。

若执行成功则返回偏移量,如果文件描述符引用的是一个管道或FIFO,则lseek返回-1,并将errno设置为EPIPE。

read函数

#include 
ssize_t read(int filedes, void *buff, size_t nbytes) ;
返回:读到的字节数,若已到文件尾为 0,若出错为-1

有多种情况可使实际读到的字节数少于要求读字节数:

  • 读普通文件时,在读到要求字节数之前已到达了文件尾端。
  • 当从终端设备读时,通常一次最多读一行
  • 当从网络读时,网络中的缓冲机构可能造成返回值小于所要求读的字节数。
  • 某些面向记录的设备,例如磁带,一次最多返回一个记录。

读操作从文件的当前位移量处开始,在成功返回之前,该位移量增加实际读得的字节数。

write函数

#include 
ssize_t write(int filedes, const void * buff, size_tn bytes) ;
返回:若成功为已写的字节数,若出错为- 1

对于普通文件,写操作从文件的当前位移量处开始。如果在打开该文件时,指定了O_APPEND选择项,则在每次写操作之前,将文件位移量设置在文件的当前结尾处。在一次成功写之后,该文件位移量增加实际写的字节数。

IO效率

缓冲区越大,读操作所需时间越短。

文件共享

UNIX支持在不同进程间共享打开文件。
内核使用了三种数据结构,它们之间的关系决定了在文件共享方面一个进程对另一个进程可能产生的影响。

  • 每个进程在进程表中都有一个记录项,每个记录项中有一张打开文件描述符表,可将其视为一个矢量,每个描述符占用一项。
  • 内核为所有打开文件维持一张文件表。
  • 每个打开文件(或设备)都有一个 v节点结构。 v节点包含了文件类型和对此文件进行各种操作的函数的指针信息。 APUE:文件IO_第1张图片
    当两个进程打开同一个文件的时候,打开此文件的每个进程都得到一个文件表项,但对一个给定的文件只有一个 v节点表项。每个进程都有自己的文件表项的一个理由是:这种安排使每个进程都有它自己的对该文件的当前位移量。
    APUE:文件IO_第2张图片
  • 使用write时,文件长度变为偏移量,文件长度加长。
  • 如果用O_APPEND标志打开了一个文件,偏移量设置为文件的长度。
  • lseek函数只修改文件表项中的当前文件位移量,没有进行任何 I / O操作。
  • 若一个文件用lseek被定位到文件当前的尾端,偏移量为文件长度。

注意区分文件描述符标志文件状态标志

原子操作

多进程也会存在竞争,如两个进程对文件尾端写数据时,已经判断文件是否创建并创建文件时,需要原子操作才能保证正确。第一种情况可以在打开文件时设置O_APPEND标志,就不需要用lseek函数。第二种open函数可以设置的O_CREAT和O_EXCL选择项。

dup和dup2函数

#include 
int dup(int filedes) ;
int dup2(int filedes, int filedes2) ;
两函数的返回:若成功为新的文件描述符,若出错为-1

dup返回一个新文件描述符,为最小可用整数。dup2返回指定的文件描述符,如果已打开,则先关闭,如果等于filedes,则不关闭。新文件描述符符与参数filedes共享同一个文件表项。(即文件状态标志和偏移量一样)

fcntl函数

fcntl函数可以改变已经打开文件的性质。

#include 
#include 
#include 
int fcntl(int filedes, int cmd,.../* int arg * / ) ;
返回:若成功则依赖于cmd(见下),若出错为-1

fcntl函数有五种功能:

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

ioctl函数

ioctl 函数是I / O操作的杂物箱。不能用本章中其他函数表示的 I / O操作通常都能用ioctl表示。终端I / O是ioctl的最大使用方面。

#include  /* SVR4 */
#include  /* 4.3+BSD * /
int ioctl(int filedes, int request, . . . ) ;
返回:若出错则为- 1,若成功则为其他

/dev/fd

打开文件/dev/fd/n等效于复制描述符n (假定描述符n是打开的)。
/dev/fd文件主要由shell使用,这允许程序以对待其他路径名一样的方式使用路径名参数来处理标准输入和标准输出。

你可能感兴趣的:(APUE)