最近在實際的開發項目遇到了一個問題,有個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>