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

svi*_*ick 14 c++ fstream iostream visual-studio-2012

我有一个已包含一些数据的文件(例如,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;
Run Code Online (Sandbox Code Playgroud)

如果我执行此代码,第一个bad()返回false,但第二个返回true,实际上没有写入任何内容.

如果我减少bytesCount到小于4096的任何值(可能是一些内部缓冲区的大小),第二个bad()返回false,但仍然没有写入.

如果我取消注释该seekp()行,则写入开始工作:bad()返回false并实际写入字节.

为什么seekp()这里有必要?没有它,为什么它不起作用?这是seekp()正确的方法吗?

我在Windows 7上使用Visual Studio 2012.

Mik*_*han 24

在MS的fstream 库从其C <stdio.h>实现继承的更新模式下打开的文件上,对读写操作的混合限制是违反限制的.

在7.19.5.3/6状态下,C标准(我引用C99,但它与C89没有区别):

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

(我的重点).

因此,您的stream.seekp(1)解决方案(即C语言fseek)是正确的.

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

MS <fstream>库在继承此限制时符合C++标准.fstreams使用basic_filebuf<charT,traits>.实现.在(C++ 11)标准对该模板的描述中,在第27.9.1.1/2节中,它只是说:

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