鉴于buffer和cache其实是不同的东西,所以我不用书上所用的概念,buffer就是buffer,cache就是cahce。不明白的小伙伴传送过去看看:看过这两张图,就明白 Buffer 和 Cache 之间区别
一、I/O buffer
相对于ISO C语言定义的标准I/O,POSIX协议定义的是unbuffered I/O。
所谓无缓冲就是指,直接调用system call (read,write)。- 对于c语言标准 I/O而言,要进行:
数据–>fwrite/fread–>用户Buffer–>write/read–>内核缓冲区–>磁盘 - 对于unix系统中的系统调用:
数据–>write/read–>内核缓冲区–>磁盘
可以看出来,其实unbuffered I/O其实还是有buffer的,只是我们看不见而已。
看似c 标准IO,还多了几步,但就速度上来说,c库还是快很多的,请看原因:
如果有过部分编程经验的话应该知道:每个系统调用到要从“用户态”,转换为“内核态”,这个过程是要消耗大量时间。
所以很多情况下程序员都需要想办法让系统调用的达到合理的次数。
在用户态下设置buffer,并测试在自己电脑或服务器上,看看哪个size是最合适的。- 对于c语言标准 I/O而言,要进行:
二、一切皆是文件
我不知道在其他unix类中是什么情况,但是
在linux中有一种思想:一切皆文件
linux把几乎所有的IO都虚拟成了一个文件,如果我要打印一份简历,我就向打印机fd写入数据。如果我要向远处的程序进行网络通信,我只需要向 socket fd写入我的数据。
2. 重要的文件描述符(File Descriptor,简称fd)
- UNIX系统shell的三个重要文件fd(括号内数字可以直接替换符号常量):
1.STDIN_FILENO(0)
2.STDOUT_FILENO(1)
3.STDERR_FILENO(2)
三、文件操作
常用文件操作函数
int open(const char *path, int oflag, …);
- int openat(int fd, const char *path, int oflag, …);
- int close(int fd);
- off_t lseek(int fd, off_t offset, int whence);
- int fcntl(int fildes, int cmd, …);
2.比较难理解的就是:lseek的whence:是三个宏定义
新的文件偏移量off_t lseek(fd, 偏移距离 dis,SEEK_XXX)
设置当前距离为cur
设置文件长度为end(当打开方式为O_APPEND时,cur也等于end)
SEEK_SET:返回的新偏移量 = 0文件起始处 + dis
SEEK_CUR:返回的新偏移量 = cur + dis
SEEK_END:返回的新偏移量 = end + dis
- 通过对比标准I/O,我发现system call有个缺点就是写入二进制文件是需要自己控制编码。
比如当我有一个结构体
struct Object
{
/*数据*/
};
/**
*当我的数据里本来就包含'\0'时,
*比如"ABCDJ12KLab\0JDLK\0djfBCjfh"(ps:这是一个完整的结构体,在内存中
*线性排列)。
*我现在必须把这个结构体完整的存入到磁盘中,于是:
*/
Object obj;
/*赋值obj*/
write(fd, (const char *)(&obj), sizeof(obj));
但是这次的system call write()仅仅写入到"ABCDJ12KLab\0"就停止了。
于是涉及到“序列化”的知识了。其实此处最简单的就是用标准I/O啊。 :)