在 *NIX 中实现 tail 的有效方法是什么?我想出了(写)两个简单的解决方案,都使用一种循环缓冲区将行加载到循环结构中(数组|双向链接循环列表-为了好玩)。我在busybox中看到了部分较旧的实现,据我所知,他们使用 fseek 来查找EOF,然后“向后”读取内容。那里有什么更清洁、更快的东西吗?我在面试时被问到这个问题,提问者看起来并不满意。先感谢您。
问问题
19514 次
4 回答
16
我认为没有与“在向前读取数据时保留最新的 N 行”或“从末尾开始并向后直到您读取第 N 行”不同的解决方案。
关键是您将根据上下文使用一个或另一个。
当tail访问随机访问文件时,或者当数据小到可以放入内存时,“走到尽头并向后退”更好。在这种情况下,运行时间被最小化,因为您扫描了必须输出的数据(因此,它是“最佳的”)
当尾部由管道馈送或数据很大时,您的解决方案(保留 N 个最新行)会更好。在这种情况下,其他解决方案会浪费太多内存,因此不实用,并且在源比 tail 慢的情况下(很可能)扫描所有文件并不重要。
于 2012-04-15T18:10:58.207 回答
8
于 2012-04-15T18:03:11.780 回答
6
首先用于fseek
查找文件结尾,然后减去 512 并减去fseek
该偏移量,然后从那里向前读取到结尾。计算换行符的数量,因为如果换行符太少,您将不得不使用减去的偏移量 1024 来做同样的事情……但在 99% 的情况下,512 就足够了。
这(1)避免了向前读取整个文件,(2)这可能比从末尾向后读取更有效的原因是向前读取通常更快。
于 2013-06-27T05:36:26.630 回答
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.*/
于 2013-06-27T05:22:04.160 回答