UNIX环境高级编程学习笔记(二)文件I/O常用函数

1.UNIX系统中的大多数文件I/O只需要用到5个函数:open、read、write、lseek和close。
2.对于UNIX内核而言,所有打开的文件都通过文件描述符引用。文件描述符是一个非负整数。打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。读写一个文件时,使用open或creat返回的文件描述符标识该文件,将其作为参数传给read或write。
3.UNIX系统shell把文件描述符0、1、2分别与进程的标准输入、标准输出和标准错误关联,替换为符号常量为STDIN_FILENO、STDOUT_FILENO、STDFERR_FILENO,这些常量在 头文件unistd.h中定义。
4.打开文件:

int open(const char *path, int oflag, ... /*mode_t mode**/);
int openat(int fd, const char *path, int oflag, ... /*mode_t mode**/);

path是要打开或创建文件的名字。oflag参数说明此函数的多个选项,由多个常量进行或运算构成。这些常量在fcntl.h中定义。
这些常量有: O_RDONLY 、 O_WRONLY、 O_RDWR、O_APPEND、O_CREAT、 O_EXCL、 O_TRUNC、O_NOCTTY、 O_NONBLOCK等。
open和openat函数返回的文件描述符一定是最小的未用描述符数值。
open 和openat函数被fd参数区分开,一共有三种可能性:

  1. path是绝对路径名,此时fd被忽略,openat函数相当于open
  2. path是相对路径名,fd指出了相对路径名在文件系统中的开始地址。fd通过打开相对路径名所在的目录来获取。
  3. path是相对路径名,fd参数具有特殊值AT_FDCWD,路径名在当前工作目录中获取,openat和open在操作上类似。

openat函数是POSIX.1最新版本中新增的一类函数之一,希望解决两个问题: a. 让线程可以使用相对路径名打开目录中的文件,而不再只能打开当前工作目录。 b. 可以避免time-of-check-to-time-of-use(TOCTTOU)错误。TOCTTOU的基本思想是:如果有两个基于文件的函数调用,其中第二个依赖于第一个调用的结果,那么程序是脆弱的。因为两个调用并不是原子操作,在两个调用之间文件可能改变了,这就造成了第一个调用的结果不在有效,使程序最终的结果是错误的。
5.创建文件:

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

此函数等效于:

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

mode为文件访问权限。creat的一个不足之处是它以只写方式打开所创建的文件。
6.关闭文件:

int close(int fd);

关闭一个文件时也释放该进程加在该文件上的所有记录锁。当一个进程终止时,内核自动关闭它所有的打开文件。
7.空洞文件:
每个打开文件都有一个与其相关联的“当前文件位移量”。它是一个非负整数,用以度量从文件开始处计算的字节数。(本节稍后将对“非负”这一修饰词的某些例外进行说明。)通常,读、写操作都从当前文件位移量处开始,并使位移量增加所读或写的字节数。按系统默认,当打开一个文件时,除非指定O_APPEND选择项,否则该位移量被设置为0。
可以调用lseek显式地定位一个打开文件。

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

对参数offset的解释与参数whence的值有关:

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

lseek也可用来确定所涉及的文件是否可以设置位移量。如果文件描述符引用的是一个管道、FIFO或网络套接字,则lseek返回-1,并将errno设置为ESPIPE。
文件的当前位移量应当是一个非负整数,但是,某些设备也可能允许负的位移量。但对于普通文件,则其位移量必须是非负值。因为位移量可能是负值,所以在比较lseek的返回值时应当谨慎,不要测试它是否小于0,而要测试它是否等于-1。
文件位移量可以大于文件的当前长度,在这种情况下,对该文件的下一次写将延长该文件,并在文件中构成一个空洞,这一点是允许的。位于文件中但没有写过的字节都被读为 0。文件的空洞不要求在磁盘上占用存储区,具体处理方式与文件系统实现有关。

8.读文件:

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

如read成功,则返回读到的字节数。如已到达文件的尾端,则返回0。有多种情况可使实际读到的字节数少于要求读字节数:

  1. 读普通文件时,在读到要求字节数之前已到达了文件尾端
  2. 当从终端设备读时,通常一次最多读一行
  3. 当从网络读时,网络中的缓冲机构可能造成返回值小于所要求读的字节数

9.写文件:

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

返回:若成功为已写的字节数,若出错为-1
其返回值通常与参数nbytes的值相同,否则表示出错。write出错的一个常见原因是:磁盘已写满,或者超过了对一个给定进程的文件长度限制。
对于普通文件,写操作从文件的当前位移量处开始。如果在打开该文件时,指定了O_APPEND选择项,则在每次写操作之前,将文件位移量设置在文件的当前结尾处。在一次成功写之后,该文件位移量增加实际写的字节数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值