如何在C ++中阅读不断增长的文本文件?

时间:2012-08-01 10:28:47

标签: c++ logging stl fstream seekg

我正在尝试从正在增长的文件中读取(类似于tail -F的内容),但我的代码必定存在一些问题:

string   log, logFile("test.log");
size_t   p = 0;

while(true)
{
    ifstream ifs(logFile.c_str());

    ifs.seekg(p);  //*1

    while(ifs.eof() == false)
    {
        getline(ifs, log);

        cout << log << endl;

        p = ifs.tellg();  //*2
    }

    nanosleep(&pause, NULL);
}

如果没有// * 1和// * 2的行,日志文件会被正确读取到最后,但如果添加了新行,则没有任何反应。

使用seekg和tellg我试图存储文件的当前结束位置,这样当我重新打开它时,我可以去那里看看已添加的内容。

我想知道我的代码有什么问题,如果真的有必要为此目的关闭并重新打开同一个文件。

谢谢。

3 个答案:

答案 0 :(得分:15)

循环不正确,因为遇到eof()tellg()返回-1并且在调用eof()之后没有立即检查getline()需要是。将循环更改为:

while (getline(ifs, log))
{
    cout << log << endl;
    p = ifs.tellg();
}

此外,当p返回size_t时,tellg()被声明为-1p的值被设置为4294967295。这意味着seekg()被设置为超出文件末尾。将p的类型更改为std::streamoff并确认对seekg()的调用是否成功:

if (ifs.seekg(p))
{
    while (getline(ifs, log))
    {
        cout << log << endl;
        p = ifs.tellg();
    }
}

  

如果确实有必要为此目的关闭并重新打开同一个文件。

不,没有必要,但您需要从流中clear() eof状态。以下是已发布代码的更正版本的替代方法:

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

int main()
{
    std::ifstream ifs("test.log");

    if (ifs.is_open())
    {
        std::string line;
        while (true)
        {
            while (std::getline(ifs, line)) std::cout << line << "\n";
            if (!ifs.eof()) break; // Ensure end of read was EOF.
            ifs.clear();

            // You may want a sleep in here to avoid
            // being a CPU hog.
        }
    }

    return 0;
}

答案 1 :(得分:3)

由于这些答案都不起作用,我想出了一个有效的方法......

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

using namespace std;

int main()
{
    string   log, logFile("test.txt");
    std::streamoff   p = 0;
    ifstream ifs(logFile.c_str());

    while(true)
    {

        ifs.seekg(p);  //*1
        while (getline(ifs, log))
        {
            cout << log << endl;
            if(ifs.tellg() == -1) p = p + log.size();
            else p = ifs.tellg();
        }
        ifs.clear();

    }
}

答案 2 :(得分:0)

此代码适用于我:

struct timespec pause;
pause.tv_sec  = 1;
pause.tv_nsec = 0;

std::ifstream ifs("test.log");
std::streamoff p;

if(ifs.is_open())
{
    std::string line;

    while(true)
    {
        if(ifs.seekg(p))
        {
            while(std::getline(ifs, line))
            {
                std::cout << line << std::endl;
                p = ifs.tellg();
            }
        }

        ifs.clear();

        nanosleep(&pause, NULL);
    }
}