今天遇到一个程序bug,A向B发送完整的一段数据,B却总是不能获取到结尾部分的内容。后来才发现在进行“write”操作(ngx.print)后还需要调用flush操作(ngx.flush)才能将数据写出。对数据IO,缓存的知识又忘光光了,这里整理一下:
对于文件描述符的操作比较简单,不同的操作系统都封装了比较好用的fstream库函数。基于流的操作最终会调用read和write函数进行IO操作,操作系统为了提升程序的运行效率,尽可能减少write和read操作的调用次数,通常会提供缓存。
缓存的类型分全缓存(读入/写出内存字节数等于缓冲区大小或者文件已经到结尾才进行IO操作,写磁盘一般是属于这种类型);行缓存(直到遇见“\n”才会进行IO操作,标准输入stdin和标准输出stdout属于这种类型);无缓存(立即进行IO,如stderr),我们可以在程序中设定流的缓存方式。
#include<stdio.h> #define SIZE 1024 void check_buf_type(){ if(stdin->_flags & _IO_UNBUFFERED) { printf("stdin unbuffered"); } else if(stdin->_flags & _IO_LINE_BUF) { printf("stdin line-buffered"); } else{ printf("stdin fully-buffered"); } printf("\n"); } int main() { check_buf_type(); char buf[SIZE]; if(setvbuf(stdin, buf, _IONBF, SIZE) != 0) { printf("error!"); return -1; } check_buf_type(); if(setvbuf(stdin, buf, _IOLBF, SIZE) != 0) { printf("error!"); return -1; } check_buf_type(); return 0; }关于缓存内容,我们在进行文件IO后,不一定保证它已经写入到磁盘或者网络套接口,存在缓存的情况下可能需要调用fflush函数强制写入磁盘文件或者fpurge清空缓存内容。
今天还遇到另外一个问题,Lua文件操作的打开模式,如下面的例子,我原本想先在文件头部写入字符串,然后再在偏移100位置处再写入字符串,可是由于中间关闭了一次,又打开后前面一次写入的内容就被清除了。示例代码如下:
local out = io.open("test","wb") out:seek("set") -- 将游标设置在文件头 out:write("Hello World") out:close() out = io.open("test","wb") out:seek("set",100) out:write("Hello World") out:close()其实这也是我文件操作方式不对导致的,“w”方式打开会将文件长度置零,改成下面的方式就可以了,“r+”表示读写方式
local out = io.open("test","wb") out:seek("set") -- 将游标设置在文件头 out:write("Hello World") out:close() out = io.open("test","rb+") out:seek("set",100) out:write("Hello World") out:close()可是需要注意的是“r+”模式不能打开一个不存在的文件,不然out会被设置为nil,所以如果要以读写方式打开,需要事先判断改文件是否存在。