UNIX_文件IO(声明于 fcntl.h 中)

文件IO系统调用 -- open、creat、close、lseek、read、write

2014-07-15 22:26:20   最后更新: 2015-02-21 15:33:37   访问数量:1314




Unix系统中大多数文件IO只需要5个函数:open、read、write、lseek、close

这些都是不带缓冲的IO,即每个read和write都调用内核中的一个系统调用,需要注意的是,这里的“不带缓冲的IO”指的是在用户的进程中对这些函数不会自动缓冲,而事实上,所有的磁盘IO都要经过内核的块缓冲区(即内核的缓冲区高速缓存),只有对原始的磁盘设备的IO例外

 

对于内核而言,所有打开的文件都通过文件描述符引用。

文件描述符是一个非负整数,当打开或创建一个文件时,内核会返回一个文件描述符。

当读或写一个文件时,使用open或creat返回的文件描述符标识该文件,将其作为参数传给read或write。

文件描述符0与进程的标准输入相关联,文件描述符1与标准输出相关联,文件描述符2与标准出错输出相关联。分别对应符号变量STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO(定义于 fcntl.h 中)。

 

打开或创建文件,定义于 fcntl.h 头文件中

int open( const char * pathname, int flags, . . . /*mode_t mode*/);

 

调用成功返回文件描述符,否则返回-1

 

第三个参数. . .表示在不同的调用中会有所不同,对于open函数,只有当程序创建文件时才会用到第三个参数,因此将具体的定义放在注释中

 

  • 第一个参数const char * pathname是打开或创建的文件名
  • 第二个参数int flags是函数执行时的选项,定义于 fcntl.h 中
mode 参数取值
参数是否必须意义
O_RDONLY只读
O_WRONLY只写
O_RDWR读写
O_APPEND 每次写时都追加到文件尾
O_CREAT 如果文件不存在,则创建文件
O_EXCL 测试文件是否存在,如不存在则创建文件,不能和O_CREAT同时指定
O_TRUNC 如果文件存在并被成功打开,并且可以写入,则先清空文件
O_NOCTTY 如果pathname参数指定的是一个终端设备,则不将该设备分配为此进程的控制终端
O_NONBLOCK 如果pathname参数指定的是一个FIFO、一个块特殊文件或一个字符特殊文件,则将本次打开操作和后续IO操作设置为非阻塞模式

mode 参数使用表中宏的一个或多个的逻辑或,三个必须的宏必选其一

 

由 open 返回的描述符值一定是最小的未用描述符值

 

创建新文件

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

 

调用成功则返回只写的文件描述符,否则返回-1

 

此函数等效于:

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

 

mode参数指定创建的文件的权限,九个访问权限位的若干个或组成,如S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH

 

关闭一个已打开的文件

int close(int fd);

 

调用成功返回0, 否则返回-1

 

当一个进程中止是,内核会自动关闭该进程所打开的所有文件,因此很多程序利用这一点而不显式调用close函数

 

每个打开的文件都有一个与之相关联的“当前文件偏移量”,通常是一个非负数,用以度量从文件开始处计算的字节数,通常文件的读写都从当前文件偏移量处开始,并且动态的改变偏移量

按照系统默认情况,打开文件时,除非指定O_APPEND选项,否则偏移量会被置位0。

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

off_t lseek(int handle, off_t offset, int whence);

 

若成功调用返回新的文件偏移量,否则返回-1

 

  1. 若whence是SEEK_SET, 则将该文件的偏移量设置为距文件开始处offset个字节
  2. 若whence是SEEK_CUR,则将该文件的偏移量设置为其当前值加offset,offset可以为正或负
  3. 若whence是SEEK_END,则将该文件的偏移量设置为文件长度加offset,offset可以为正或负

可以通过 off_t currpos = lseek (fd, 0, SEEK_CUR); 来确定所打开的文件是否可以设置偏移量(调用后判断currpos是否为-1)

lseek只将偏移量记录与内核中,而不进行任何IO操作。

文件偏移量可以大于文件当前长度,在这种情况下,对该文件的下一次写入将造成文件中包含空洞,对于空洞的处理方式与具体的文件系统有关,一般不分配磁盘块,读取时会被读为0

对于有空洞的文件,ls -l命令会读到文件开头到尾端的总长度,与没有空洞的相同文件是一样的,而du -s命令则读到该文件所使用磁盘空间的总量,以512字节块或1024字节块为单位,将返回比ls -l小的值,而对有空洞的文件进行复制后的文件将没有空洞,所有空洞被用0填充

 

从打开的文件中读取数据

int read(int fd, void * buf, size_t count);

 

如果read成功则返回读到的字节数,如已到达文件结尾,则返回0,出错则返回-1

 

当从终端设备读时,一般一次最多读一行(但有方法可以使其一次可读多行)

 

向打开的文件写数据

int write(int fd, void *buf, int nbyte);

 

返回写入的字节数(即nbyte,如若不等,说明出错),否则返回-1

 

从当前文件偏移量开始写起,若指定了O_APPEND选项,则设置文件偏移量为文件结尾

写入结束后,当前文件偏移量增加相应字节

 

pread 和 pwrite 函数

ssize_t pread(int fd, void *buf, size_t count, off_t offset);

 

ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);

 

调用这两个函数后并不更新文件指针,与先执行lseek()后执行read()或write()类似,但这两个函数是原子性的

 

标准输入输出文件描述符:STDIN_FILENO、STDOUT_FILENO

 






技术帖      linux      unix      c++      cpp      c语言      龙潭书斋      apue      unix环境高级编程      io      file      open      creat      close      lseek      read      write     


1#哈喽: (回复)2018-03-17 15:46:25

向大佬学习,虽然现在感觉学这个工作中的作用不明显,也知道这些是基础,待我把工作中的技能熟练后,在来这里探路

京ICP备15018585号