web-dev-qa-db-ja.com

fstream seekg()、seekp()、およびwrite()

ファイルへの書き込み時にseekg()およびseekp()がどのように機能するかについての明確化を探しています。たとえば、次のようなファイルがあったとします。

_offset 0: 2
offset 4: 4
offset 8: 6
offset 12: 8
offset 16: 10
_

ここで、ファイルを開き、値の読み取りと書き込みを行うためのシークをいくつか行います。

_fstream file;
file.open("file.txt", fstream::in |fstream::out | fstream::binary);
file.seekp(0, ios::end) // seek to the end of the file
int eofOffset = file.tellp(); // store the offset of the end-of-file, in this case 20

int key = 0;

file.seekg(12, ios::beg); // set the seek cursor to offset 12 from the beginning of the file
file.read((char *) &key, (int)sizeof(int)); // read in the next 4 bytes and assign it to key, in this case 8
file.seekg(8, ios::beg); // set the seek cursor to offset 8 from the beginning of the file
file.read((char *) &key, (int)sizeof(int)); // read in the next 4 bytes and assign it to key, in this case 6
_

次に、ファイルの最後に書き込みたいと思います。 seekg()関数はシークカーソルのみを移動するので、私のseekp()カーソルはまだファイルの最後になければなりませんか?そう:

_int newKey = 12;
file.write((char *) &newKey, sizeof(int));
_

ファイルは次のようになります。

_offset 0: 2
offset 4: 4
offset 8: 6
offset 12: 8
offset 16: 10
offset 20: 12
_

オフセットを探し、その値を、挿入されたばかりの値へのオフセットとして書き込むと、ファイルはどうなりますか。たとえば、そのオフセットに12を挿入したので、_offset 8_に_eofOffset = 20_を保持させます。

私が行った場合:

_file.seekp(8, ios::beg);
file.write((char *) &eofOffset, sizeof(int));
_

ファイルを次のように正しく書き換えますか?

_offset 0: 2
offset 4: 4
offset 8: 20
offset 12: 8
offset 16: 10
offset 20: 12
_

seekg()およびseekp()関数を使用してエラーが発生した場合はお知らせください。

21
raphnguyen

クラステンプレートstd::basic_filebufは単一のファイル位置を保持します

§27.9.1.1

  1. クラスbasic_filebufは、入力シーケンスと出力シーケンスの両方をファイルに関連付けます。
  2. クラスbasic_filebufのオブジェクトによって制御されるシーケンスの読み取りおよび書き込みの制限は、標準CライブラリFILEを使用した読み取りおよび書き込みの制限と同じです。
  3. 特に:
    • ファイルが読み取り用に開かれていない場合、入力シーケンスを読み取ることができません。
    • ファイルが書き込み用に開かれていない場合、出力シーケンスを書き込むことはできません。
    • ジョイントファイルの位置は、入力シーケンスと出力シーケンスの両方で維持されます。

これが意味することは、デフォルトでstd::basic_fstreamを使用するstd::basic_filebufを使用すると、単一のファイル位置がseekp()seekg()の両方によって移動されることです。別の変数を使用してポジションの1つを保存してからそのシークに戻さない限り、プットポジションとゲットポジションを個別に追跡することはできません。

ポイント2の意味は、fstreamの読み取りと書き込みの間で、出力から入力に変更するときにバッファーをフラッシュするか、ファイル位置をシークする必要があり、ファイルの最後にあるかシークする必要があることです。入力から出力に変更するときのファイルの位置。

これらの制限の詳細については、C99標準のセクション7.19.5.3/7(「fopen関数」)、またはC11の7.21.5.3/7を参照してください。

22
user657267