本章开始讨论UNIX系统的文件I/O函数,包括打开文件、读文件、写文件等。
UNIX系统中的大多数文件I/O只需要用到5个函数:open、read、write、lseek和close。它们每执行一次都会调用内核中的系统调用,也就是常说的不带缓冲的I/O函数。
只要涉及多个进程间共享资源(比如同时读写某个文件),原子操作的概念就变得很重要,我将通过open()函数来讨论此概念。
一、文件描述符
文件描述符是一个非负整数,每一个使用open()函数打开的文件都会分配一个文件描述符。
在第一章提到的标准输入、标准输出、标准错误分别对应文件描述符0、1、2。
每个操作系统中的文件描述符个数都是一定的,我们可以使用如下shell命令查看最大文件描述符数值:
$ ulimit -n
也可使用下面的代码进行查看:
1 #include <unistd.h> 2 3 sysconf(_SC_OPEN_MAX)
二、文件操作函数
UNIX系统中的大多数文件I/O只需要用到5个函数:open、read、write、lseek和close。我在下面给出它们的函数声明、例子和函数作用:
1 /* 文件打开函数 */ 2 #include <fcntl.h> 3 4 int open(const char *path, int oflag, ... /* mode_t mode */ ); 5 int openat(int fd, const char *path, int oflag, ... /* mode_t mode */ ); 6 7 /* 例子 */ 8 int fd = open("a.txt", O_RDWD | O_CREAT, 0666); 9 if (fd == -1) /* 失败 */ 10 return -1;
函数参数以及返回值:
path:需要打开文件的路径
oflag:打开文件的权限(比如是否可以读、是否可以写等)
mode:创建文件(O_CREAT)的权限,0666表示用户权限、组权限和其他人权限,我将在下面介绍
返回值:成功返回文件描述符;出错返回-1
关于oflag的定义一般有以下几类,不同类之间可以如上面例子,使用“|”组合。常用的我会使用加粗字体。
O_RDONLY、O_WRONLY、O_RDWR、O_EXEC:只读、只写、既可以读也可以写、只执行
O_APPEND:追加到文件的尾部
O_CREAT:如果没有名为path的文件,就会创建此文件
O_TRUNC:如果此文件存在,而且以只写或读写打开,将其长度截断为0,也就是删除文件内容
在我们使用shell命令ls -al时,会显示文件的权限,如:
drwxr-xr-x 2 lioker lioker 4096 7月 6 2017 Music
drwxr-xr-x其中的d表示目录,d后面的rwx表示用户权限为7(rwx分别用二进制表示,如果有权限为1,没有权限为0);rwx后面的r-x表示组中没有写权限,为5,其他人权限与组权限相同。
1 /* 文件读写函数 */ 2 #include <unistd.h> 3 4 ssize_t read(int fd, void *buf, size_t nbytes); 5 ssize_t write(int fd, const void* buf, size_t n); 6 7 /* 例子 */ 8 int res; /* 用来接收读写文件的返回值 */ 9 char buf[20] = "Hello World"; 10 11 res = write(fd, buf, strlen(buf)); 12 printf("Write Bytes: %d\n", res); 13 14 res = read(fd, buf, sizeof(buf)); 15 printf("Read Bytes: %d\n", res);
函数参数以及返回值:
fd:文件打开函数返回的文件描述符
buf:读/写变量数据
nbytes:需要读的大小
n:需要写的长度
返回值:成功返回实际读写的字节数;出错返回-1
如果读者执行上面两行代码,会发现read函数返回的是0。
这是由于文件有一个与其关联的“文件偏移量”,用于表示当前文件读/写到哪里。这个偏移量我们可以使用lseek函数控制。
1 /* 文件偏移量控制 */ 2 #include <unistd.h> 3 4 off_t lseek(int fd, off_t offset, int whence); 5 6 /* 例子 */ 7 lseek(fd, SEEK_SET, 0);
原文:https://www.cnblogs.com/Lioker/p/10642216.html