概述
在用c++的fstream
时遇到一个很奇怪的问题,记录和分析过程如下。
需求
两个文件,一个122k(file-bak),一个100k(file),file
是file-bak
的前100k的内容,需要从file-bak
里读取后面的22k数据,写入file
的后面,然后对比file
和file-bak
,数据应该一致。
c++实现
实现1
打开ofile
后调用:ofile.seekp(102400, ios::beg)
1 |
|
编译运行如下:
1 | # g++ -std=c++11 -o fstream_tst fstream_tst.cc |
结果异常
实现2
打开ofile
后调用:ofile.seekp(0, ios::end)
1 |
|
编译运行如下:
1 | # g++ -std=c++11 -o fstream_tst fstream_tst.cc |
结果异常
很奇怪为啥 ofile.seekp(0, ios::end); 后 ofile.tellp() 的输出为0
实现3
打开ofile
时指定:std::ios_base::out | std::ios_base::binary | std::ios_base::app
1 |
|
编译运行如下:
1 | # g++ -std=c++11 -o fstream_tst fstream_tst.cc |
结果正常
c实现
代码如下:
1 |
|
编译运行如下:
1 | # gcc -o fstream_tst fstream_tst.c |
结果正常
分析
用c++代码的实现1
分析如下:
1 | # strace ./fstream_tst |
从上面可以看出编译后的可执行文件在打开要写入的文件时调用的是:open("file", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
好奇怪为啥译后可执行文件执行open系统调用加了truncate标记!
网上搜索了好久,没找到相关的解释,于是翻看《C++ Primer》圣书,找到如下说明,也明白了原因:
- 默认
ofstream
流对象关联的文件将以out模式
打开,使文件可写;以out模式
打开的文件会被情况:丢弃该文件存储的所有数据; - 所以从效果上来看,为
ofstream
对象指定out模式
等效于同时指定了out和trunc模式
针对分析到的原因,修改代码如下:
1 |
|
编译运行如下:
1 | # gcc -o fstream_tst fstream_tst.c |
结果正常
结论
经过这么大半天的测试分析查找,稍微明白了C++的fstream
的使用,还真是不能直接想当然的拿C的那一套来推测。。。坑啊!
参考
http://www.runoob.com/cplusplus/cpp-files-streams.html
https://stackoverflow.com/questions/34238063/c-seekp0-iosend-not-working
https://stackoverflow.com/questions/29593940/why-is-an-fstream-truncated-when-it-is-opened-with-the-flags-iosate-and-ioso
https://social.msdn.microsoft.com/Forums/vstudio/en-US/8f121287-539f-4fe1-96b6-db3e5b9306f4/vc10-using-stdofstream-truncates-file-without-trunc