我有一个已包含一些数据的文件(例如,8 kB)。我想从文件的开头读取一些内容,然后从我读完的地方开始覆盖数据。所以我尝试使用以下代码:
std::fstream stream("filename", std::ios::in | std::ios::out | std::ios::binary);
char byte;
stream.read(&byte, 1);
// stream.seekp(1);
int bytesCount = 4096;
auto bytesVec = std::vector<char>(bytesCount, 'c');
char* bytes = bytesVec.data();
std::cout << stream.bad() << std::endl;
stream.write(bytes, bytesCount);
std::cout << stream.bad() << std::endl;
如果我执行此代码,则第一个bad()
返回false
,但第二个返回true
,实际上没有任何内容被写入。
如果我将bytesCount
减少到小于4096的任何值(可能是某个内部缓冲区的大小),则第二个bad()
会返回false
,但仍然没有写入任何内容。
如果我取消注释seekp()
行,则写入开始工作:bad()
返回false
并且实际写入字节。
为什么这里需要seekp()
?没有它,为什么它不起作用? seekp()
是否正确地执行此操作?
我在Windows 7上使用Visual Studio 2012。
答案 0 :(得分:23)
你对阅读和混音的限制违反了规定
在以MS的fstream
更新模式打开的文件上写操作
库继承自其C <stdio.h>
实现。
C标准(我引用C99,但这与C89没有区别) 在7.19.5.3/6州:
以更新模式打开文件时('+'作为第二个或第三个字符) 在上面的模式参数值列表中,输入和输出都可以在上面执行 相关流。但是,如果没有输入,输出不应直接输入 干预调用fflush函数或文件定位函数(fseek, fsetpos,或倒带),输入不应直接跟随输出而不用 干预调用文件定位功能,除非输入操作遇到结束 - 的文件。
(我的重点)。
因此,您的stream.seekp(1)
解决方案(转换为C fseek
)是正确的。
GNU C库没有此标准限制,因此您发布的代码有效 与GCC一起建造的预期。
MS <fstream>
库在继承时符合C ++标准
这个限制。 fstream
是使用basic_filebuf<charT,traits>
实现的。在(C ++ 11)标准对该模板的描述中,在第27.9.1.1/2节中,它只是说:
读取和编写由basic_filebuf类对象控制的序列的限制与使用标准C库FILE读取和写入的限制相同。
答案 1 :(得分:1)
您可能希望查看绑定的流 - http://www.cplusplus.com/reference/ios/ios/tie/
这使得每次输入读取输出都会自动刷新,这是我认为你想要的行为,虽然它确实需要一个单独的输入和输出流