C语言 如何有效地实现tail?

bfrts1fy  于 2022-12-22  发布在  其他
关注(0)|答案(5)|浏览(215)

在 *NIX中实现tail的有效方法是什么?我提出(编写)了两个简单的解决方案,都使用某种循环缓冲区将行加载到循环结构(数组)中|双向链接循环列表--为了好玩)。我在busybox中看到过一部分旧的实现,据我所知,他们使用fseek来查找EOF,然后“反向”读取内容。有没有更干净更快的东西?我在面试中被问到这个问题,asker看起来并不满意。提前感谢你。

voase2hg

voase2hg1#

我不认为有什么解决方案不同于“向前阅读数据时保留最新的N行”或“从末尾开始向后读取,直到读取第N行”。
关键是你会根据上下文使用一个或另一个。
当tail访问一个随机访问文件时,或者当数据小到足以放入内存时,“走到最后并向后”更好。在这种情况下,运行时间最小化,因为您扫描了必须输出的数据(因此,它是“最优的”)
你的解决方案(保留N个最新的行)是更好的,当尾巴是由管道或当数据是巨大的。在这种情况下,另一个解决方案浪费太多的内存,所以它是不切实际的,在这种情况下,源比尾巴慢(这是可能的)扫描所有的文件并不那么重要。

jum4pzuy

jum4pzuy2#

从文件末尾向后读取,直到读取到N换行符或到达文件开头。
然后打印刚才读取的内容。
我认为这里不需要任何花哨的数据结构。
如果你感兴趣的话。

vcirk6k6

vcirk6k63#

首先使用fseek找到文件的结尾,然后减去512和fseek到那个偏移量,然后从那里向前读到结尾。计算换行符的数量,因为如果太少,你将不得不用减去的偏移量1024**...做同样的事情,但是在99%的情况下512就足够了。
(1)避免了向前阅读整个文件,并且(2)**这可能比从末尾向后读取更有效的原因是向前读取通常更快。

rkttyhzu

rkttyhzu4#

/ *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.*/
bjp0bcyl

bjp0bcyl5#

//author: jvk
#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[])
{
     FILE *fp;
     int beg,count=10,i=0;
     char ch,line[100];
     fp = fopen(argv[1], "r");
     //to hold the begining of the file
     beg = ftell(fp);
     //read file backwards
     fseek(fp,0,SEEK_END);
     // moving file pointer such that it points to at begining of last 
ten lines of file
     while(count && ftell(fp)!= beg)
     {
         ch = getc(fp);
         if(ch=='\n')
         {
             count--;
         }
         i--;
         //moving backwards.
         fseek(fp,i,SEEK_END);
     }
     //printing from current position of fp.
     while(fgets(line,sizeof(line),fp) != NULL)
     {
         printf("%s",line);
     }
     fclose(fp);
     return 0;
}

相关问题