最近发现了自己网站一个bug(早发现了,一直没去深入探索原因),我网站的图标没了,按F12看看图标传过来了吗,发现传过来了。但为啥没显示出来百思不得其解,起初是怀疑图片是二进制文件保存的,所以按正常文件读写是不对的,想了之后决定用sendfile函数(Linux的一个系统函数,也叫零拷贝函数,没用过的同学可以翻翻man手册或者搜搜了解一下)发送二进制文件,对jpg、png来一个判断,然后sendfile直接发送,这样做起来改动是最少的,该完之后确实发现ok了,就放在那里没改了,最近要修改一下网站后台的源码,决定重新挖掘一下原因,记录一下这个bug。
如果读二进制文件,C语言的fopen,打开方式需要指定一个b,表示binary以二进制的文件打开。C++需要ios::binary来打开(在unix类系统中,ios::binary写不写貌似都可以,我查资料显示的是针对windows平台对换行符做了特殊的处理)
这是一份处理正确的代码,seekg移动到末尾,来看一下文件的大小,然后在移到起始位置来读文件。在进行写入文件
int succeful(){
ifstream is("1.jpeg", ifstream::in | ios::binary);
is.seekg(0, is.end);
int length = is.tellg();
is.seekg(0, is.beg);
char * buffer = new char[length];
is.read(buffer, length);
ofstream os("111.jpeg",ofstream::out | ios::binary);
if(!os.is_open()){
cout << "写入文件未打开" << endl;
return -1;
}
os.write(buffer,length);
delete [] buffer;
is.close();
os.close();
}
上述代码是正确的,我们写C++都知道cout也是一个流对象,我可以cout << “XXXXXX”,上面写入文件os也是可以 os << buffer
的,天真的我这么做了发现了又出bug了,拷贝文件失败了。为什么会失败捏?因为char*遇到’\0’是会自动停止输出的,而write指定输出长度所以就算遇到了‘\0’也不会停下来的
又解决了一个难题,你以为结束了吗?不并没有,我的网站用的是string类型读文件,而不是char*,当我把buffer赋值给string对象,天真的我以为一切正常,凌晨三点的我准备关机睡觉,结果一运行发现竟然是错的
改动如下:
string s = buffer;
if(!os.is_open()){
cout << "写入文件未打开" << endl;
return -1;
}
// os.write(s.c_str(),length);
// os.write(s.c_str(),s.size());
os << s;
write也不对,size也不对、length也不对、os直接输出也不对,当时我内心为啥阿咋回事,我起初以为c_str()用的不对,后来忘了看那篇文章了,提了一句stirng构造函数,我就明白了,因为在构造string对象的时候char*遇到\0就结束了,所以string数据是不正确的,string s(buffer,length);改成这样子就OK了。string的小坑,之前确实没注意string的构造函数,也没注意到’\0’引发的问题
read二进制记住不能用strlen这样的函数来判断读取的字节数,可以用fstat函数获取一下文件大小,然后string构造的时候,string s(str,n),给s一个长度值,这样string构造的时候不会遇到\0结束了