第 3 章 文件 I/O

文件 I/O

文件创建与打开

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
int creat(const char *pathname, mode_t mode);
int openat(int dirfd, const char *pathname, int flags);
int openat(int dirfd, const char *pathname, int flags, mode_t mode);

open 与 openat 的区别在于,openat 支持指定文件目录然后 pathname 为相对于指定目录的文件路径,flags 有许多规则,读写打开类型、追加、不存在则创建,是否非阻塞打开、写是否等待物理 IO 完成,等等

create 创建文件

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int creat(const char *pathname, mode_t mode);

close 关闭文件

#include <unistd.h>
int close(int fd);

注意的是,关闭一个文件还会释放此进程在文件上加的锁、当一个进程终止时其打开的文件将会被关闭

lseek 调整文件偏移量

#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
//offset为移动的偏移量
//偏移量根据whence来说,SEEK_SET文件开始、SEEK_CUR当前位置、SEEK_END文件末尾

lseek 仅将当前的文件的偏移量记录在内核,不会引起 IO 操作、文件偏移量可以大于文件的当前长度

空洞文件

read 读取数据

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);

返回读出的字节数、读到文件末尾返回 0,出错返回-1。当从网络读取时,网络中的缓冲机制可能造成返回值小于所要求读的长度,千万不要用 size_t 接收 read 返回参数,因为 read 可能返回-1

write 写数据

#include<unistd.h>
ssize_t write(int fd,const void*fd,size_t nbytes);

成功返回已经写的字节数、出错返回-1

函数 pread 与 pwrite

#include <unistd.h>
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);
//两个函数不会改变文件的offset,只是从指定的offset读

dup 和 dup2 函数

用于复制文件描述符

#include <unistd.h>
int dup(int oldfd);
int dup2(int oldfd, int newfd);//当oldfd==newfd时返回newfd

//----------------------------------------
//open时会先分配最小的没用的fd
close(1);
fd = open(FILE,O_WRONLY|O_CREAT|O_TRUNC,0600);
puts("hello");//输出到了FILE中
//与
fd = open(FILE,O_WRONLY|O_CREAT|O_TRUNC,0600);
close(1);
dup(fd);//效果一样,只不过后者将fd副本复制到fd 1上
//但不能保证close与dup的原子性
//所以有了函数dup2
dup2(fd,1);//close(1);dup(fd);

不同的文件描述符指向同一个内核中维护的文件表

sync、fsync、fdatasync 同步函数

#include <unistd.h>
void sync(void);
int fsync(int fd);
int fdatasync(int fd);

sync 只是将修改过的块缓冲区排入写队列,然后返回、并不等待实际磁盘写完毕再返回
fync 支持同步文件属性修改与文件数据,而 fdatasync 只支持数据,二者等待磁盘实际操作 OK 后再返回,可以保证数据一致性

fcntl 函数用于修改已经打开文件的属性

#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );

功能主要有
1、复制一个已有的描述符
2、获取与设置文件描述符标志
3、获取设置文件状态标志 就是以 O_开头的一些宏如 O_RDWR 等
4、获取设置异步 IO 所有权
5、获取设置记录锁

ioctl 函数:IO 操作杂物箱,后面再学,一般用得少

#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);

/dev/fd/是一个虚目录,当前进程的描述符信息

fd=open("/dev/fd/0",O_RDWR) //标准输入

将得到文件指针所对应的文件描述符

int fileno(FILE *stream);

截断文件到指定长度大小

#include <unistd.h>
#include <sys/types.h>
int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length);