使用相同的fstream读取和写入同一文件

时间:2013-07-08 21:48:25

标签: c++ visual-studio-2012 iostream fstream

我有一个已包含一些数据的文件(例如,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。

2 个答案:

答案 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/

这使得每次输入读取输出都会自动刷新,这是我认为你想要的行为,虽然它确实需要一个单独的输入和输出流