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が、2 番目は返さtrueれ、実際には何も書き込まれません。

bytesCount4096 (おそらく内部バッファーのサイズ) よりも小さい値に減少すると、2 番目は をbad()返しますfalseが、それでも何も書き込まれません。

行のコメントを外すseekp()と、書き込みが開始されます。bad()戻りfalse、バイトが実際に書き込まれます。

なぜseekp()ここで必要なのですか?それがないと機能しないのはなぜですか?seekp()これを行う正しい方法はありますか?

Windows 7 で Visual Studio 2012 を使用しています。

4

2 に答える 2

28

MS のライブラリが C実装fstream から継承した更新モードで開かれたファイルに対する読み取り操作と書き込み操作の混在に関する制限に違反しています。<stdio.h>

C 標準 (私は C99 を引用しますが、この点では C89 と違いはありません) 7.19.5.3/6 には次のように記載されています。

ファイルが更新モード (上記のモード引数値のリストの 2 番目または 3 番目の文字として「+」) で開かれると、関連するストリームで入力と出力の両方が実行される場合があります。ただし、fflush 関数またはファイル配置関数 (fseek、fsetpos、または巻き戻し)への呼び出しを介在させずに、出力の直後に入力を続けてはならず、ファイル配置への呼び出しを介在させずに、入力の直後に出力を続けてはなりません。 function、入力操作がファイルの終わりに遭遇しない限り。

(私の強調)。

したがってstream.seekp(1)、 Cfseekに発展するあなたの解決策は正しいです。

GNU C ライブラリにはこの標準的な制限がないため、投稿されたコードは GCC でビルドすると期待どおりに動作します。

MS<fstream>ライブラリは、この制限を継承して C++ 標準に準拠しています。fstreamを使用して実装されbasic_filebuf<charT,traits>ます。このテンプレートの (C++11) 標準の説明では、§ 27.9.1.1/2 で、次のように単純に述べています。

クラス basic_filebuf のオブジェクトによって制御されるシーケンスの読み取りと書き込みに関する制限は、標準 C ライブラリ FILE での読み取りと書き込みの場合と同じです。

于 2013-07-10T09:47:15.643 に答える
2

結ばれたストリームを調べることをお勧めします - http://www.cplusplus.com/reference/ios/ios/tie/

これにより、入力が読み取られるたびに出力が自動的にフラッシュされます。これは、必要な動作だと思いますが、個別の入力ストリームと出力ストリームが必要です

于 2014-10-28T17:16:40.423 に答える