引言
大多数文件I/O只需用到5个函数:
- open
- read
- write
- lseek
- close
文件描述符
当打开一个现有文件或创建一个新文件时,内核向进程返回一个文件描述符。
当读、写一个文件时,使用open或create返回的文件描述符标识该文件,将其作为参数传送给read或write。
文件描述符的符号常量:(输入0、输出1、错误2)
- STDIN_FILENO
- STDOUT_FILENO
- STDERR_FILENO
文件描述符的变化范围为0~OPEN_MAX-1,现在很多系统将OPEN_MAX定为64
函数open和openat
作用:打开或创建一个文件
两个函数的返回值:
- 若成功,返回文件描述符(一定是最小的未用描述符数值)
- 若出错,返回-1
open
int open(const char *path,int oflag),... /*mode_t mode */);
- path为要打开或创建文件的名字
- oflag用来说明此函数的多个选项(读,写,执行等)
openat
int openat(int fd,const char *path,int oflag),... /*mode_t mode */);
openat多了个fd参数,有三种可能性:
- path参数指定的是绝对路径名,在这种情况下,fd参数被忽略,openat函数相当于open
- path参数指定的是相对路径名,fd参数指出了相对路径名在文件系统中的开始地址。fd参数是通过打开相对路径名所在的目录来获取
- path参数指定了相对路径名,fd参数具有特殊值AT_FDCWD。在这种情况下,路径名在当前工作目录中获取,openat函数再操作上与open函数类似。
函数creat
作用:创建一个新文件(只写方式)
int creat(const char *path,mode_t mode);
等价于:open(path, O_WRONLY | O_CREAT | O_TRUNC,mode);
mode为访问权限
creat函数的返回值:
- 若成功,返回只写方式打开的文件描述符(一定是最小的未用描述符数值)
- 若出错,返回-1
函数close
作用:关闭一个打开文件
int close (int fd);
函数lseek
先了解一个概念,当前文件偏移量:度量从文件开始处计算的字节数,通常用来从文件中找到所用数据。
lseek函数就是用来设置偏移量的
off_t lseek(int fd,off_t offset,int whence);
返回值:
- 成功:返回新的文件偏移量
- 出错:返回-1
whence有三个选项:
- SEEK_SET:相对文件开始处+offset字节
- SEEK_CUR:相对当前位置+offset字节
- SEEK_END:相对文件长度+offset字节
文件偏移量可以大于文件当前长度,这时,下一次写该文件的时候会加长该文件,并在文件中构成一个空洞,这是允许的,位于文件中但没有写过的字节都读为0。
文件中的空洞部分不占磁盘上的存储区,具体处理方式与文件系统的实现有关。
Ex:
apue.h的解决方法请参照:
http://blog.csdn.net/u011391629/article/details/69677019
myerror.h的解决办法是
http://blog.chinaunix.net/uid-29179071-id-4117644.html
#include "apue.h"
#include <fcntl.h>
#include <myerror.h>
int main(void)
{
char buf1[] = "abcdefghij";
char buf2[] = "ABCDEFGHIJ";
int fd;
if((fd = creat("file.hole", FILE_MODE)) < 0 )
err_sys("creat error");
if(write(fd, buf1, 10) != 10)
err_sys("buf1 write error");
/* offset now = 10 */
if(lseek(fd, 16384, SEEK_SET) == -1)
err_sys("lseek error");
/* offset now = 16384 */
if(write(fd, buf2, 10) != 10)
err_sys("buf2 write error");
/* offset = 16394 */
exit(0);
}
用od -c file.hole 观察实际内容
0000000 a b c d e f g h i j \0 \0 \0 \0 \0 \0
0000020 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0
…
0040000 A B C D E F G H I J
0040012
无空洞文件file.hole占用8个磁盘块,再创建一个与file.hole同样长度但无空洞的文件file.nohole,占用20个磁盘块。
函数read
ssize_t read(int fd,void *buf,size_t nbytes);
返回值:
- 读到的字节数(若已到文件尾,返回0)
- 出错,返回0
函数write
ssize_t write(int fd,const void *buf,size_t nbytes);
返回值:
- 成功:返回已写字节数(通常和nbytes的值相同)
- 出错:返回-1(通常是磁盘已写满,或超过了一个给定进程的文件长度限制)