终于进入正题了,本章介绍的文件I/O是不带缓冲的I/O函数,不是ISO C的组成部分,直接对应于系统调用(因为是POSIX.1和SUS的组成部分)
基本的不带缓冲的I/O
本章列举的I/O函数是POSIX标准而不是ISO C标准,每个函数直接对应一个系统调用,因此可以认为他们就是系统调用接口。
open / openat
二者的函数原型为
#include <fcntl.h> //需要的oflag常量宏定义
int open(const char *path, int oflag, ...)
int openat(int fd, const char *path, int oflag, ...)//fd是相对路径名在文件系统的在开始地址,需要通过打开相对路径名所在的目录来获取
简单的调用实例
1 #include <unistd.h>
2 #include <fcntl.h>
3 #include <stdio.h>
4
5 int
W> 6 main(int argc, char** argv)
7 {
8 int fd;
9 fd = open("./test",O_RDWR);
10 printf("The file descriptor of the file using system call is %d",fd);
11 return 0;
12 }
关于openat的访问,实例如下
1 #include <unistd.h>
2 #include <fcntl.h>
3 #include <stdio.h>
4
5 int
W> 6 main(int argc, char** argv)
7 {
8 int path_fd, file_fd;
9 if ((path_fd = open("/home/wfs/cpp",O_RDONLY|O_DIRECTORY)) == -1) printf("open direct failed\n");
10 else if ((file_fd = openat(path_fd,"test_openat",O_RDWR|O_TRUNC|O_CREAT))== -1) printf("open file failed in direct %d\n",path_fd);
11 else
12 printf("The file descriptor of the file in direc %d using system call is %d\n",path_fd,file_fd);
13 return 0;
14 }
但是这个写法是有问题的,因为是creat打开,所以创建的新文件具有写保护,第二次打开的时候会无法打开,猜测是mode参数未设置的原因,之后再研究。
返回文件描述符(最小的未使用的描述符值)。
openat的引入可以解决
- 相对路径访问
- 避免TOCTTOU (Time of check to time of use):两个函数调用有依赖关系,且都涉及文件读取,那么后调用的函数所依赖的第一个函数的结果可能是无效的因为文件会在调用间隙被改写。
close
#include <unistd.h>
int close (int fd);
进程终止时,内核会关闭它打开的所有文件
lseek
关于偏移量的系统调用接口,可以认为就是当前文件的光标位置,但是与光标不一样的是它可以大于文件长度,下次写的时候会直接从偏移的位置开始写,上一次的文件末尾与新写的位置之间会出现空洞,虽然不占用磁盘空间,但是文件长度事实上是增加了空洞的大小。
这里有一个用法的测试实例
1 #include <unistd.h>
2 #include <stdio.h>
3
4 int main()
5 {
6 if (lseek(STDIN_FILENO,0,SEEK_CUR)== -1) printf("cannot lseek stdin\n");
7 else printf("yes ok!");
8 return 0;
9 }
书上有一句话
lseek仅将当前文件的偏移量记录在内核当中,并不引起I/O操作。
这里我认为有两层意思
- 在当前进程运行过程中,偏移量是由当前进程所对应的内核空间维护的,只有发生系统调用write/read/lseek时才会发生变化。
- 当前进程退出之后,或者该文件关闭描述符也回收之后偏移量不会被保存的。
read 和write
读写文件的示例
1 #include <unistd.h>
2 #include <stdio.h>
3 #include <fcntl.h>
4
5 #define READBUFFER_SIZE 100
6 #define WRITEBUFFER_SIZE 20
7
8 int main()
9 {
10 int fd;
11 char* readbuf;
12 char writebuf[WRITEBUFFER_SIZE];
13 if ((fd = open("./test",O_RDWR | O_APPEND))== -1) printf("open file failed\n");
14 else {
15 int readbyes_num;
16 if ((readbyes_num=read(fd,readbuf,READBUFFER_SIZE))== -1) {
17 printf("error when read");
18 _exit(0);
19 }
20 int i;
21 for (i = 0; i < readbyes_num; ++i) printf("%c",readbuf[i]);
22 printf("\n");
23 printf("The old file has been printed above, now we begin to write something new to it\n");
24 for (i=0; i<READBUFFER_SIZE;++i) writebuf[i] = 'f'+i;
25 int writebytes_num;
26 if ((writebytes_num= write(fd,writebuf,WRITEBUFFER_SIZE)) == -1) {
27 printf("error when write");
28 _exit(0);
29 }
30 printf("write finished!\n");
31 }
32 return 0;
33 }