文件IO(一)
文件描述符(file descriptor)
Linux下一切是文件,当打开一个或创建一个文件时,内核向进程返回一个文件描述符,用来标识该文件。
unix将文件描述符0,1,2分别于标准输入、标准输出和标准错误关联。
unistd.h中是这么定义的
/* Standard file descriptors. */
#define STDIN_FILENO 0 /* Standard input. */
#define STDOUT_FILENO 1 /* Standard output. */
#define STDERR_FILENO 2 /* Standard error output. */
持有权限
文件自身有可读可写可执行权限(rwx),除此之外,也限制了进程持有文件这个行为本身的权限(只读、只写等)
/* open/fcntl. */
#define O_RDONLY 00
#define O_WRONLY 01
#define O_RDWR 02
/* 以上三个选其一 */
/* 以下为可选项 */
#ifndef O_CREAT /* 不存在则创建 */
# define O_CREAT 0100 /* Not fcntl. */
#endif
#ifndef O_EXCL
# define O_EXCL 0200 /* Not fcntl. */
#endif
#ifndef O_NOCTTY
# define O_NOCTTY 0400 /* Not fcntl. */
#endif
#ifndef O_TRUNC /* 如文件存在,且为O_WRONLY或O_RDWR成功打开,将其长度截断为0 */
# define O_TRUNC 01000 /* Not fcntl. */
#endif
#ifndef O_APPEND /* 写追加 */
# define O_APPEND 02000
#endif
#ifndef O_NONBLOCK
# define O_NONBLOCK 04000
#endif
#ifndef O_SYNC
# define O_SYNC 04010000
#endif
#ifdef __USE_XOPEN2K8
# define O_DIRECTORY __O_DIRECTORY /* Must be a directory. */
# define O_NOFOLLOW __O_NOFOLLOW /* Do not follow links. */
# define O_CLOEXEC __O_CLOEXEC /* Set close_on_exec. */
#endif
打开、关闭、偏移函数
open
#include <fcntl.h>
int open(const char *path, int oflag, ...);
int openat(int fd, const char *path, int oflag, ...);
creat
#include <fcntl.h>
int creat(const char *path, mode_t mode);
close
#include <unistd.h>
int close(int fd);
lseek
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
//注:出错均返回-1
1.open
创建一个临时文件、先写该文件、然后又读该文件, 可以这样实现
open(path, O_RDWR | O_CREAT | O_TRUNC, mode);
2.creat
等效为:
open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
因此不再需要单独的creat函数。
3.close
关闭一个文件会释放该进程加在该文件上的所有记录锁。
此外,进程终止,内核会关闭它所有的打开文件。
4.lseek
文件读写都是从当前文件偏移量(current file offset)开始的,并使偏移量增加所读写的字节数
从unistd.h头文件中能找到如下定义
/* Values for the WHENCE argument to lseek. */
#ifndef _STDIO_H /* <stdio.h> has the same definitions. */
# define SEEK_SET 0 /* Seek from beginning of file. */
# define SEEK_CUR 1 /* Seek from current position. */
# define SEEK_END 2 /* Seek from end of file. */
#endif
常用如下方式确定打开文件的当前偏移量
lseek(fd, 0, SEEK_CUR);
如果文件描述符指向的是一个管道、FIFO、网络套接字,则返回-1
if (-1 == lseek(STDIN_FILENO, 0, SEEK_CUR))
printf("cannot seek\n");
else
printf("seek OK\n");
exit(0);
那么重点来了!
读写函数
read
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t nbytes);
write
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t nbytes);
//注:出错均返回-1
拿书上给的例子测试一下,从标准输入读取,写到标准输出里
#include "apue.h"
#define BUFFSIZE 4096
int main()
{
int n;
char buf[BUFFSIZE];
while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
if (n != write(STDOUT_FILENO, buf, n))
err_sys("write error");
if (n < 0)
err_sys("read error");
exit(0);
}
上面是常用的文件IO函数,不带缓冲的IO(unbuffered I/O),实际上使用了内核中的系统调用