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

How to read a growing text file in C++?

本文关键字:不断增长 文本 文件 读取 C++      更新时间:2023-10-16

我正试图从一个正在增长的文件中读取(类似于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,我正在尝试存储文件的当前结束位置,这样当我重新打开它时,我就可以在那里查看添加的内容。

我想知道我的代码中出了什么问题,以及是否真的有必要为此关闭并重新打开同一个文件。

谢谢。

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

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

此外,当tellg()返回-1时,由于p被声明为size_t,所以p的值被设置为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;
}

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

#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();
    }
}

这个方法对我来说非常有效:

#include <string>
#include <chrono>
#include <thread>
#include <fstream>
#include <iostream>
int main(int, char* argv[])
{
    // open file passed in on command line (at end of file)
    std::ifstream ifs(argv[1], std::ios::ate);
    if(!ifs.is_open())
    {
        std::cerr << "ERROR: opening log file: " << argv[1] << 'n';
        return 1;
    }
    // remember file position
    std::ios::streampos gpos = ifs.tellg();
    std::string line;
    bool done = false;
    while(!done)
    {
        // try to read line
        if(!std::getline(ifs, line) || ifs.eof())
        {
            // if we fail, clear stream, return to beginning of line
            ifs.clear();
            ifs.seekg(gpos);
            // and wait to try again
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
            continue;
        }
        // remember the position of the next line in case
        // the next read fails
        gpos = ifs.tellg();
        // process line here
        std::cout << "line: " << line << std::endl;
    }
}

此代码适用于我:

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);
    }
}