UNIX系统 ---- 文件I/O

一、文件描述符

对于内核而言,所有打开文件都由文件描述符引用。文件描述符是一个非负整数。当打开一个现存文件或创建一个新文件时,内核向进程返回一个文件描述符。当读、写一个文件时,用open或creat返回的文件描述符标识该文件,将其作为参数传送给read或write。

二、open函数

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

int open(const char *pathname , int oflag,... , /*mode_t mode8/ );
  • pathname是要打开或创建的文件的名字。
  • 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操作完成。

由open返回的文件描述符一定是最小的未用描述符数字。

三、creat函数

可用creat函数创建一个新文件。

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

此函数等效于:

open(pathname, O_WRONL|YO_CREAT|O_TRUNC, mode);

所以现在creat函数已经被open所代替了,几乎不再使用它了~

四、close函数

可用close函数关闭一个打开文件。

int close(int filedes);

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

五、lseek函数

每个打开文件都有一个与其相关联的“当前文件位移量”。它是一个非负整数,用以度量从文件开始处计算的字节数。通常,读、写操作都从当前文件位移量处开始,并使位移量增加所读或写的字节数。按系统默认,当打开一个文件时,除非指定O_APPEND选择项,否则该位移量被设置为0。可以调用lseek显式地定位一个打开文件。
可以调用lseek显式地定位一个打开文件。

off_t lseek(int filedes, off_t offset, int whence);
  • 若whence是SEEK_SET,则将该文件的位移量设置为距文件开始处offset个字节。
  • 若whence是SEEK_CUR,则将该文件的位移量设置为其当前值加offset, offset可为正或负。
  • 若whence是SEEK_END,则将该文件的位移量设置为文件长度加offset, offset可为正或负。
    lseek仅将当前的文件位移量记录在内核内,它并不引起任何I/O操作。然后,该位移量用于下一个读或写操作。

六、read函数

用read函数从打开文件中读数据。

ssize_t read(int filedes, void *buff, size_t nbytes);

如read成功,则返回读到的字节数。如已到达文件的尾端,则返回0。

七、write函数

用write函数向打开文件写数据。

ssize_t write(int filedes, const void *buff, size_t nbytes);

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

八、文件共享

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

  • 每个进程在进程表中都有一个记录项,每个记录项中有一张打开文件描述符表,可将其视为一个矢量,每个描述符占用一项。与每个文件描述符相关联的是:
    • 文件描述符标志。
    • 指向一个文件表项的指针。
  • 内核为所有打开文件维持一张文件表。每个文件表项包含:
    • 文件状态标志(读、写、增写、同步、非阻塞等)。
    • 当前文件位移量。
    • 指向该文件v节点表项的指针。
  • 每个打开文件(或设备)都有一个 v节点结构。 v节点包含了文件类型和对此文件进行各种操作的函数的指针信息。

九、dup和dup2函数

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

int dup(int filedes);
int dup2(int filedes, int filedes2);

由dup返回的新文件描述符一定是当前可用文件描述符中的最小数值。用dup2则可以用filedes2参数指定新描述符的数值。如果filedes2已经打开,则先将其关闭。如若filedes等于filedes2,则dup2返回filedes2,而不关闭它。这些函数返回的新文件描述符与参数filedes共享同一个文件表项。

十、fcntl函数

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

int fcntl(int filedes, int cmd,.../*int arg*/);
  • 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)。
  • 命令值解释:
    • F_DUPFD 复制文件描述符filedes,新文件描述符作为函数值返回。
    • F_GETFD 对应于filedes的文件描述符标志作为函数值返回。
    • F_SETFD 对于filedes设置文件描述符标志。新标志值按第三个参数 (取为整型值)设置。
    • F_GETFL 对应于filedes的文件状态标志作为函数值返回。
    • F_SETFL 将文件状态标志设置为第三个参数的值(取为整型值)。
    • F_GETOWN 取当前接收SIGIO和SIGURG信号的进程ID或进程组ID。
    • F_SETOWN 设置接收SIGIO和SIGURG信号的进程ID或进程组ID。

十一、ioctl函数

ioctl函数是I/O操作的杂物箱。不能用本章中其他函数表示的I/O操作通常都能用ioctl表示。

int ioctl(int filedes, int request, ...);

十二、 /dev/fd

比较新的系统都提供名为/dev/fd的目录,其目录项是名为0、1、2等的文件。打开文件/dev/fd/n等效于复制描述符n (假定描述符n是打开的)。

参考文献《UNIX环境高级编程》

发布了20 篇原创文章 · 获赞 8 · 访问量 5578

猜你喜欢

转载自blog.csdn.net/weixin_44816732/article/details/104200055