基本思想是,从文件末尾向前Seek N个字符,读入内存,如果达到了tail n行则读取结束,如果不够n行再从文件末尾向前Seek N+N*2^1个字符,并读取N*2^1个字符,加上之前的行数,如果还不够tail n行,继续直到N+N*2^1+...+N*2^m以满足tail n为止。
#include <iostream> #include <fstream>
#include <string>
#include <list>
int tail(const std::string & fname, std::list<std::string> & ls, int lines, int bytes=100)
{
std::fstream fs(fname.c_str());
if(!fs)
return -1;
int status=0;
fs.seekg(0,std::ios_base::end);
std::streamoff old_pos=fs.tellg();
std::streamoff last_pos=old_pos-bytes*lines;
fs.seekg(last_pos,std::ios_base::beg);
std::string line;
std::list<std::string>::const_iterator cit=ls.begin();
while(true)
{
std::getline(fs,line);
cit=ls.insert(cit,line);
++cit;
if(status==0)
{
if(fs.eof())
{
if(ls.size()>lines)
break;
old_pos=last_pos;
last_pos>>=1;
fs.clear();
fs.seekg(last_pos,std::ios_base::beg);
std::streamoff temp=fs.tellg();
ls.erase(--cit);
cit=ls.begin();
status=1;
}
}
else if(status > 0)
{
if(fs.tellg() >= old_pos)
{
if(ls.size() > lines)
break;
old_pos=last_pos;
last_pos>>=1;
fs.seekg(last_pos,std::ios_base::beg);
ls.erase(--cit);
cit=ls.begin();
}
}
}
if(ls.size()>lines)
{
int i=ls.size()-lines;
for(;i>0;--i)
ls.erase(ls.begin());
}
return ls.size();
}
int main(int argc, char * argv[])
{
std::list<std::string> ls;
tail(argv[1],ls,atoi(argv[2]));
std::copy(ls.begin(),ls.end(),std::ostream_iterator<std::string>(std::cout,"/n"));
return 0;
}