第三章
本章主要讲了文件的I/O操作
Unix下主要有五个系统API接口用于操控文件,分别是
open
、 read
、write
、lseek
、 close
,顾名思义,分别是用于打开、读取、写入、内部定位、关闭文件。文件描述符
File Descriptors通常为一个非负整数,可以用于表示任何类型的文件(文件夹也是一种特殊的文件),操作系统的文件操作API通常以文件描述符作为参数。
参数选项
头文件
<fcntl.h>
中定义了一些常量,用作下面这些函数的参数,第一类参数选项为读写方式的选择,这些选项是互斥的| 名称 | 意义 |
| -------- | ---------- |
| O_RDONLY | 只读模式 |
| O_WRONLY | 只写模式 |
| O_RDWR | 读写模式 |
| O_EXEC | 仅执行模式 |
| O_SEARCH | 仅搜索模式 |
第二类选项则为随意选择,由于数量众多,再次仅选一部分介绍
| 名称 | 意义 |
| ----------- | ------------------------------------------ |
| O_APPEND | 在文件末尾追加 |
| O_CLOEXEC | 设定“在多线程调用时不重复打开该文件”的FLAG |
| O_CREAT | 如果文件不存在则创建文件 |
| O_DIRECTORY | 指定目标为目录,非目录则报错 |
| O_EXCL | 创建文件时如果文件已经存在则报错 |
| O_NOFOLLOW | 如果指向符号链接则报错 |
打开文件
open
函数和openat
函数#include <fcntl.h>int open(const char *path, int oflag, ... /* mode_t mode */ );int openat(int fd, const char *path, int oflag, ... /* mode_t mode */ );
Open函数即为最基本的
打开文件
函数,在早期的Unix版本中仅仅用于打开文件,后来随着Unix版本演进,拥有了许多其他的功能。这里简单解释一下上述两个函数的区别:
open
函数为基础的打开文件
函数,可用于任何类型的文件,功能也正如其名,打开文件,然后你就可以对文件进行各种操作了。Openat
函数解决了open
函数所不能解决的一个问题,那就是在多线程的情况下,在对一个文件进行open
的同时,该文件所在的目录可能被其他的线程或进程修改,而如果使用openat
函数的话,该目录会被锁定,这样系统API调用者就不用每次都检测该目录是否存在了。创建文件
creat
函数#include <fcntl.h>int creat(const char *path, mode_t mode);
早起的Unix系统下的
open
函数仅仅具备打开文件的功能,因此,一个单独的creat
系统调用就显得十分必要,因为有了这个函数才能创建新的文件,而后来随着Unix系统的发展,creat
的功能和指定了O_WRONLY|O_CREAT|O_TRUNC
的open
函数有这相同的功能。关闭文件
#include <unistd.h>int close(int fd);
关闭文件的实质就是释放文件上所加的锁,释放了锁之后,其他的程序便可以对该文件进行相应的读写操作了。
文件内部定位
#include <unistd.h>off_t lseek(int fd, off_t offset, int whence);
每个文件都有一个
当前文件偏移量
,它通常来说是一个非负整数,用于表明当前j进行操作文件中的具体位置。使用 lseek
可以把处理位置移动到指定的偏移量处。在调用lseek
函数时可以使用一些FLAG,SEEK_SET
表示移动到文件头+offset值的位置, SEEK_CUR
表示移动到当前偏移量+offset值的位置, SEEK_END
表示移动到文件末尾+offset值的位置。对于后两个FLAG,offset的值可以为负。另外,
lseek
函数仅仅可以被用在普通文件上,对于管道、FIFO(命名的管道)、socket,则不能使用lseek
。