seekp()声明似乎是不必要的,但实际上并非如此

时间:2016-06-13 11:00:11

标签: c++ file-access

以下代码适用于双向流,并从文件中查找记录ID,然后从该文件中替换该记录的内容。但在覆盖内容之前,它会将put指针移动到get指针的位置。通过tellp()tellg(),我们发现他们在转移之前已经处于同一位置。但是在删除seekp()行时,代码不会覆盖数据。

data.txt中的内容:

123 408-555-0394
124 415-555-3422
263 585-555-3490
100 650-555-3434

代码:

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main()
{
    int inID = 263;
    const string& inNewNumber = "777-666-3333";
    fstream ioData("data.txt");

    // Loop until the end of file
    while (ioData.good()) {
        int id;
        string number;

        // Read the next ID.
        ioData >> id;

        // Check to see if the current record is the one being changed.
        if (id == inID) {
            cout << "get pointer position " << ioData.tellg() << endl; //Displays 39
            cout << "put pointer position " << ioData.tellp() << endl; //Displays 39
            ioData.seekp(ioData.tellg()); //Commenting this line stops code from working
            ioData << " " << inNewNumber;
            break;
        }

        // Read the current number to advance the stream.
        ioData >> number;
    }

    return 0;
}

问题:

当put和指针一起移动时,有什么需要使用seekp()来移动put指针的位置?

2 个答案:

答案 0 :(得分:2)

@Revolver_Ocelot在评论中链接的问题提供了相关信息。最重要的部分是您必须在读写访问之间进行刷新或寻找。因此,我以下列方式修改了您的代码:

if (id == inID) {
    cout << "get pointer position " << ioData.tellg() << endl; //Displays 39
    cout << "put pointer position " << ioData.tellp() << endl; //Displays 39
    ioData.flush();
    cout << "get pointer position " << ioData.tellg() << endl;
    cout << "put pointer position " << ioData.tellp() << endl;
    ioData.seekp(ioData.tellg()); //Commenting this line stops code from working
    ioData << " " << inNewNumber;
    break;
}

这给出了以下有趣的输出:

  

获得指针位置39
  指针位置39
  得到指针位置72
  指针位置72

(调用flush()实际上并没有解决问题。我只是将它添加到您的代码中,以便向您显示它修改了文件指针。)

我对您的原始代码的假设如下:如果您在首先读取文件后写入文件,而不在其间调用seekp(),那么在实际数据之前,写入命令会修改文件指针写入文件。我假设write命令执行某种类型的刷新,并且它以与我添加到代码中的flush()命令类似的方式修改文件指针。

当我在PC上运行上面的代码时,flush()命令将文件指针移动到位置72.如果我们从原始代码中删除seekp()命令,我认为写命令将在实际写入文件之前,还要将文件指针移动到位置72(或者可能是另一个无效位置)。在这种情况下,写入失败,因为位置72位于文件末尾。

因此,需要ioData.seekp(ioData.tellg());来确保文件指针设置为正确的文件位置,因为当您在不调用seekp()的情况下在读取和写入文件之间切换时,它可能会发生变化。 / p>

this answer的最后一段给出了类似的解释。

答案 1 :(得分:1)

这是因为如果有人想要从输入操作转换到输出操作,它是c ++双向流的规则。然后必须使用seek()函数进行此类转换。

这个功能是从c语言的核心借用的,因为每当有人使用双向流时,程序员可能正在使用两个不同的缓冲区,其中一个缓冲区可用于输入,另一个缓冲区用于输出。现在同步两个缓冲区将是性能低效的解决方案。由于大多数时候程序员可能不需要同时使用输入和输出功能,程序将无缘无故地为程序员维护两个缓冲区。

作为替代方案,实现了另一个解决方案,让程序员通过调用seek()函数显式执行刷新和其他管理。

这意味着我们经常使用的seek()函数不仅可以重新定位文件指针,还可以更新缓冲区和流。

另见 why fseek or fflush is always required between reading and writing in the read/write "+" modes