文件描述符
文件描述符通常是一个小的非负整数,内核用以标识一个特定进程正在访问的文件。
当内核打开一个文件或创建一个新文件时,它都返回一个文件描述符,用以读写文件。
每当运行一个程序时,所有的shell都为其打开三个文件描述符——标准输入(standard input)&标准输出(standard output)&标准错误(standard error)。
两个常量STDIN_FILENO和STDOUT_FILENO定义在头文件<unistd.h>中,它们指定了标准输入和标准输出的文件描述符,在POSIX标准中,它们的值分别是0和1。
六个函数
>open函数
功能:打开或创建一个文件
#include <fcntl.h>
int open( const char *path, int oflag, .../*mode_t mode*/ );
open 成功则返回文件描述符,出错则返回 -1
path: 要打开的文件、设备的路径名
oflag: 由多个选项进行或运算构造oflag参数
必选:O_RDONLY(read only), O_WRONLY(write only), O_RDWR(read and write);
可选:O_APPEND(每次写是追加在文件尾端)
O_CREAT(文件不存在即创建它,使用该选项需要第三个参数mode来指定打开文件的权限模式)
O_EXCL(用于测试一个文件是否存在,如果不存在则创建此文件)
// 文件已存在时,同时指定 O_EXCL 和 O_CREAT 会出错。
O_TRUNC(如果文件存在,而且为只写或者读写成功打开,则将其长度截短为0)
O_BOCTTY(如果 path 指的是终端设备,则不将该设备分配作为此进程的控制终端)
O_NONBLOCK (如果 path 是一个 FIFO 、块设备、字符特殊文件,则此选项为文件的本次打开和后续 I/O 操作设置非阻塞模式方式)
>creat函数
功能:创建一个新文件
#include <fcntl.h>
int creat( const char *path, mode_t mode );
creat 成功则返回为只写打开的文件描述符,出错则返回 -1
此函数等价于 open( pathname, O_WRONLY | O_CREAT | O_TRUNC, mode );
>close函数
功能:关闭打开的文件
#include <unistd.h>
int close( int fd );
colse 成功则返回0,出错则返回 -1
>lseek函数
功能:设置文件偏移量
#include <unistd.h>
off_t lseek ( int fd, off_t offset, int whence);
lseek 成功做返回新的文件偏移量,若出错则返回 -1
whence: SEEK_SET (将该文件的偏移量设置为距文件开始处 offset 个字节)
SEEK_CUR (将该文件的偏移量设置为距当前偏移量 offset 个字节处,offset 可以为负)
SEEK_END (将该文件的偏移量设置为文件长度加 offset 个字节,offset 可以为负)
存疑:offset为负问题
若 lseek 成功执行,则返回新的文件偏移量,因此 lseek 可以用来确定打开文件的当前偏移量,或确定所涉及的文件是否可以设置偏移量。如果文件描述符引用的是一个管道、FIFO 或网络套接字,则 lseek 返回 -1,并将 errno 设置为 ESPIPE。
注意:由于某些设备允许负的文件偏移量,即返回负值时并不一定是 lseek 出错,所以在比较 lseek 的返回值时最好测试它是否等于 -1。
>read函数
功能:从打开的文件中读数据
#include <unistd.h>
ssize_t read( int fd, void *buf, size_t nbytes );
read 成功则返回读到的字节数,出错则返回 -1
read 函数返回值为实际读到的字节数,所以不一定等于指定的读入字节数 nbytes。(读普通文件时在读到 nbytes 个字节前已经读到了文件尾端 | 从终端设备读入的字节限制 | 从网络读时的网络缓冲机制影响 | 从管道或FIFO读时管道包含的字节数小于 nbytes | 从某些面向记录的设备读时的字节限制 | 信号中断而数据部分未读)
>write函数
功能:向打开的文件中写数据
#include <unistd.h>
ssize write( int fd, );
write 函数的返回值通常与参数 nbytes 相同,否则表示出错。write出错的一个常见原因是:磁盘已写满,或者超过了一个给定进程的文件长度限制。
注意:对于普通文件,读操作和写操作都是从文件的当前偏移量开始,所以在调用 read 和 write 函数时一定要注意文件的当前偏移量位于文件的什么位置。(如果在打开文件时,指定了 O_APPEND 选项,则在每次操作之前,该文件的偏移量位于文件的当前结尾处,在一次成功写入之后,该文件的偏移量增加实际写的字数。)
一个实例
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char **argv){
int fd;
char buf1[] = "write successfully.";
char buf2[] = "*******************";
if((fd = open("forExample", O_RDWR | O_APPEND | O_CREAT, 0777)) < 0)
printf("open error\n");
printf("fd = %d\n", fd);//标准输入、输出、出错分别是0、1、2,于是fd取现在的最小数3
if(write(fd, buf1, sizeof(buf1)) != sizeof(buf1))
printf("write error\n");
//此时文件偏移量在文件尾
if(read(fd, buf2, sizeof(buf2)) < 0)
printf("first read error");
printf("first read:buf2 = %s\n", buf2);
lseek(fd, 0, SEEK_SET);
//此时文件偏移量在文件头
if(read(fd, buf2, sizeof(buf2)) < 0)
printf("second read error");
printf("second read:buf2 = %s\n", buf2);
//此时文件偏移量位于文件尾
lseek(fd, -14, SEEK_CUR);
//此时文件偏移量位于距离文件尾-6个字节处
memset(buf2, 0, sizeof(buf2));
if(read(fd, buf2, 7) < 0)
printf("third read error");
printf("third read:buf2 = %s\n", buf2);
close(fd);
return 0;
}
运行结果:
forExample文件内容:
为了体现代码中 open 函数选项的作用(再次打开时在文件尾端追加写入),再运行一次: