17

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

4

2 回答 2

28

您违反了对以更新模式打开的文件混合读取和写入操作的限制,MS 的fstream 库继承自其 C<stdio.h>实现。

7.19.5.3/6 的 C 标准(我引用 C99,但在这一点上与 C89 没有区别)指出:

当以更新模式打开文件时(“+”作为上述模式参数值列表中的第二个或第三个字符),可以在关联的流上执行输入和输出。但是,如果没有对 fflush 函数或文件定位函数(fseek、fsetpos 或 rewind)的干预调用,则输出不应直接跟随输入,并且在没有对文件定位的干预调用的情况下,输入不应直接跟随输出function,除非输入操作遇到文件结尾。

(我的重点)。

因此,您的stream.seekp(1)解决方案转移到 Cfseek是正确的。

GNU C 库没有此标准限制,因此您发布的代码在使用 GCC 构建时可以按预期工作。

MS<fstream>库在继承此限制方面符合 C++ 标准。fstreams 是使用 实现的basic_filebuf<charT,traits>。在 (C++11) 标准对该模板的说明中,第 27.9.1.1/2 节中,它简单地说:

读取和写入由类 basic_filebuf 的对象控制的序列的限制与使用标准 C 库 FILE 读取和写入的限制相同。

于 2013-07-10T09:47:15.643 回答
2
于 2014-10-28T17:16:40.423 回答