在* NIX中实现tail的有效方法是什么? 我提出(写)两个简单的解决方案,都使用一种循环缓冲区将线加载到圆形结构(数组|双向链接循环列表 - 为了好玩)。 我在busybox中看到了部分较旧的实现,从我的理解,他们使用fseek找到EOF,然后“向后”阅读东西。那里有更清洁,更快的东西吗? 我在面试时被问到这个问题并且提问者看起来并不满意。提前谢谢。
答案 0 :(得分:14)
我不认为有一些解决方案不同于“在读取数据时保留最新的N行”或“从最后开始并向后移动直到您阅读第N行”。
关键是你要根据情境使用一个或另一个。
当tail访问随机访问文件时,或者当数据足够小以便放入内存时,“走到最后并向后”会更好。 在这种情况下,运行时最小化,因为您扫描必须输出的数据(因此,它是“最佳”)
当尾部通过管道输送或数据量巨大时,您的解决方案(保留N条最新线路)会更好。 在这种情况下,另一种解决方案浪费了太多内存,因此它不实用,如果源比尾部慢(这很可能),扫描所有文件并不重要。
答案 1 :(得分:7)
答案 2 :(得分:6)
首先使用fseek
找到文件结尾然后将512和fseek
减去该偏移量,然后从那里向前读取结束。计算换行符的数量,因为如果太少,则必须使用1024 ... 的减去偏移量进行相同的操作,但在99%的情况下,512就足够了。
这(1)避免向前阅读整个文件,(2)之所以可能比从最后向后阅读更有效的原因是前进是通常更快。
答案 3 :(得分:0)
/ *This example implements the option n of tail command.*/
#define _FILE_OFFSET_BITS 64
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <getopt.h>
#define BUFF_SIZE 4096
FILE *openFile(const char *filePath)
{
FILE *file;
file= fopen(filePath, "r");
if(file == NULL)
{
fprintf(stderr,"Error opening file: %s\n",filePath);
exit(errno);
}
return(file);
}
void printLine(FILE *file, off_t startline)
{
int fd;
fd= fileno(file);
int nread;
char buffer[BUFF_SIZE];
lseek(fd,(startline + 1),SEEK_SET);
while((nread= read(fd,buffer,BUFF_SIZE)) > 0)
{
write(STDOUT_FILENO, buffer, nread);
}
}
void walkFile(FILE *file, long nlines)
{
off_t fposition;
fseek(file,0,SEEK_END);
fposition= ftell(file);
off_t index= fposition;
off_t end= fposition;
long countlines= 0;
char cbyte;
for(index; index >= 0; index --)
{
cbyte= fgetc(file);
if (cbyte == '\n' && (end - index) > 1)
{
countlines ++;
if(countlines == nlines)
{
break;
}
}
fposition--;
fseek(file,fposition,SEEK_SET);
}
printLine(file, fposition);
fclose(file);
}
int main(int argc, char *argv[])
{
FILE *file;
file= openFile(argv[2]);
walkFile(file, atol(argv[1]));
return 0;
}
/*Note: take in mind that i not wrote code to parse input options and arguments, neither code to check if the lines number argument is really a number.*/