【问题标题】:fstream seekg(), seekp(), and write()fstream seekg()、seekp() 和 write()
【发布时间】:2013-03-18 05:07:19
【问题描述】:

我正在寻找有关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

现在,如果我选择寻找偏移量并将其值作为偏移量写入刚刚插入的值,我的文件会发生什么情况。例如,我希望 offset 8 保留 eofOffset = 20,因为我们刚刚在该偏移量处插入了 12。

如果我这样做:

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() 函数时出现任何错误,请告诉我。

【问题讨论】:

    标签: c++ file-io fstream seekg


    【解决方案1】:

    类模板std::basic_filebuf保存单个文件位置

    § 27.9.1.1

    1. basic_filebuf 类将两个输入关联 序列和带有文件的输出序列。
    2. 对由类 basic_filebuf 的对象控制的序列的读写限制与 使用标准 C 库文件进行读写。
    3. 特别是:
      • 如果文件未打开,则无法读取输入序列。
      • 如果文件未打开以进行写入,则无法写入输出序列。
      • 为输入序列和输出序列维护一个联合文件位置。

    这意味着当您使用std::basic_fstream(默认情况下使用std::basic_filebuf)时,单个文件位置会同时移动seekp()seekg();除非您使用单独的变量来存储其中一个位置,以便您随后可以回溯到它,否则您无法独立跟踪 put 和 get 位置。

    第 2 点的含义是,在 fstream 上的读取和写入之间,当从输出更改为输入时,您必须刷新缓冲区或查找文件位置,并且您必须位于文件末尾或查找从输入更改为输出时的文件位置。

    有关这些限制的详细信息,请参阅 C99 标准的第 7.19.5.3/7 节(“fopen 函数”)或 C11 的第 7.21.5.3/7 节。

    【讨论】:

    • 谢谢!那么你什么时候建议刷新缓冲区呢?你会在每次读写后刷新它,还是让它保持原样,就像你正在进行一系列读取或一系列写入一样?
    • @raphnguyen 刷新缓冲区是一项相对昂贵的操作,通常不需要手动刷新,除非您从写入切换到读取并且您不查找,除非您有充分的理由刷新让实现处理其他刷新。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-29
    • 1970-01-01
    • 1970-01-01
    • 2013-12-28
    • 2023-03-18
    • 1970-01-01
    相关资源
    最近更新 更多