你如何有效地实现尾部?

时间:2012-04-15 18:00:14

标签: c linux unix tail

在* NIX中实现tail的有效方法是什么? 我提出(写)两个简单的解决方案,都使用一种循环缓冲区将线加载到圆形结构(数组|双向链接循环列表 - 为了好玩)。 我在busybox中看到了部分较旧的实现,从我的理解,他们使用fseek找到EOF,然后“向后”阅读东西。那里有更清洁,更快的东西吗? 我在面试时被问到这个问题并且提问者看起来并不满意。提前谢谢。

4 个答案:

答案 0 :(得分:14)

我不认为有一些解决方案不同于“在读取数据时保留最新的N行”或“从最后开始并向后移动直到您阅读第N行”。

关键是你要根据情境使用一个或另一个。

当tail访问随机访问文件时,或者当数据足够小以便放入内存时,“走到最后并向后”会更好。 在这种情况下,运行时最小化,因为您扫描必须输出的数据(因此,它是“最佳”)

当尾部通过管道输送或数据量巨大时,您的解决方案(保留N条最新线路)会更好。 在这种情况下,另一种解决方案浪费了太多内存,因此它不实用,如果源比尾部慢(这很可能),扫描所有文件并不重要。

答案 1 :(得分:7)

从文件末尾向后读取,直到读取N换行符或到达文件的开头。

然后打印刚读过的内容。

我不认为这里需要任何花哨的数据结构。

Here is the source code of tail如果你有兴趣的话。

答案 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.*/