最近在实际的开发项目遇到了一个问题,有个24小时在跑的Linux程序,会不断有日志输出,写到一个指定的日志文件中。但是,日志只提供了输出的功能,并没有读取日志文件的功能。如果给程序员自己看日志是很简单的,只需要用tail 或 vi 即可。但是现在有个需求,需要在程序的界面上显示日志文件的内容,而且是最近的100行记录。在网上搜索了一遍,总结一下:
1:从文件头开始,先用getline函数获取每一行,然后再丢弃前面的数据。
我:不行,日志文件有可能几百MB,全部读一篇再丢弃是行不通的。
2:自己先计算文本有多少行,然后再截取。
我:没有找到具体的实现代码,而且我正在读取这个文件时有可能程序正在输出日志,不能随意破坏文件的输出。
最终没找到合适解决方案,我自己的思路是这样的:
1:打开文件
2:将文件指针移到最后。
3:反向搜索换行符,如果达到100行则停止搜索了。
4:根据当前位置再将一行行记录读取放到vector里。
5:现在可以将vector里的记录进行处理。
实现后发现反向读取100的内容还是很快的,0.1毫秒都不用,当然,这要看一行的内容有多少。
而且代码中并不真正去读取字符,只是用C++的io输入流中的peek函数查看数据,效率提高了。
代码如下:
---------------------
std::ifstream fin( "/var/log/test.log" , std::ios::ate );
if( !fin )
{
cerr<<"打开日志文件失败!";
return -1;
}
// 先倒回文件末尾两个字符
fin.seekg(-2, fin.cur);
// 假定反向读取100行记录
int lineCount = 100;
for(int i = 0; i < lineCount; i++)
{
// 查看前一个字符是否为回车符
while( fin.peek() != fin.widen('\n') )
{
fin.seekg(-1, fin.cur );
}
// 走到这里表示跳过一行了,所以继续跳直到够100行
fin.seekg(-1, fin.cur);
}
fin.seekg(2, fin.cur);
// 现在文件指针指向99行的末尾,可以读取了
vector<string> result;
std::string line;
while( getline(fin, line) )
{
//cout <<"新入一行 : "; << line << endl;
result.push_back( line );
}
fin.clear();
fin.close();
</string>