Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 您将如何有效地实施tail?_C_Linux_Unix_Tail - Fatal编程技术网

C 您将如何有效地实施tail?

C 您将如何有效地实施tail?,c,linux,unix,tail,C,Linux,Unix,Tail,实现tail-in*NIX的有效方法是什么? 我提出(写)了两个简单的解决方案,都使用一种循环缓冲区将行加载到循环结构中(数组|双链接循环列表-为了好玩)。 我在busybox中看到了旧实现的一部分,据我所知,他们使用fseek查找EOF,然后“向后”阅读。外面有更干净更快的吗? 我在采访中被问到这个问题,问者看起来并不满意。提前谢谢。从文件末尾向后读取,直到读取了N换行符或到达文件开头 然后打印刚才读到的内容 我认为这里不需要任何花哨的数据结构 如果您感兴趣。我认为没有什么解决方案可以与“在向

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

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

然后打印刚才读到的内容

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


如果您感兴趣。

我认为没有什么解决方案可以与“在向前读取数据时保留最新的N行”或“从末尾开始,然后向后直到读取第N行”不同

关键是,您可以根据上下文使用一个或另一个

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

当tail使用管道或数据量很大时,您的解决方案(保留N条最新的行)会更好。
在这种情况下,另一种解决方案浪费了太多内存,因此不实用,而且在源代码比tail慢的情况下(很可能),扫描所有文件并不重要。

/
*此示例实现tail命令的选项n.*/

#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.*/
定义文件偏移量64位
#包括
#包括
#包括
#包括
#包括
#包括
#定义BUFF_尺寸4096
文件*打开文件(常量字符*文件路径)
{
文件*文件;
file=fopen(文件路径,“r”);
if(file==NULL)
{
fprintf(stderr,“打开文件时出错:%s\n”,文件路径);
出口(errno);
}
报税表(档案);
}
无效打印行(文件*文件,离线)
{
int-fd;
fd=文件号(文件);
国际nread;
字符缓冲区[BUFF_SIZE];
lseek(fd,(startine+1),SEEK_集);
而((nread=read(fd,buffer,BUFF_SIZE))>0)
{
写入(标准输出文件号、缓冲区、nread);
}
}
void walkFile(文件*文件,长N行)
{
关闭位置;
fseek(文件,0,SEEK_END);
fposition=ftell(文件);
关闭索引=F位置;
off_t end=F位置;
长计数线=0;
煤焦;
对于(索引;索引>=0;索引--)
{
cbyte=fgetc(文件);
如果(cbyte=='\n'&(end-index)>1)
{
countlines++;
if(countlines==nlines)
{
打破
}
}
位置--;
fseek(文件、定位、搜索集);
}
打印行(文件、位置);
fclose(文件);
}
int main(int argc,char*argv[])
{
文件*文件;
file=openFile(argv[2]);
walkFile(文件,atol(argv[1]);
返回0;
}
/*注意:请记住,我没有编写代码来解析输入选项和参数,也没有编写代码来检查lines number参数是否真的是数字*/

首先使用
fseek
找到文件的结尾,然后减去512和
fseek
到该偏移量,然后从那里向前读取到结尾。计算换行次数,因为如果换行次数太少,则必须使用1024的减去偏移量来计算换行次数,但在99%的情况下,512就足够了


(1)避免了向前读取整个文件,而(2)这可能比从末尾向后读取效率更高的原因是向前读取通常更快。

我喜欢这个问题,因为它是学习编程(以及一般的系统内容)时非常重要的一课。有些操作本质上是不可能有效执行的,至少没有给出您正在处理的数据的标准表示形式(在本例中,是从一开始就开始的线性字节流文件)。学习简单地从数据的格式中认识到这一点,并避免将不能有效地协同工作的数据和操作配对,这是学习编写高效软件的关键部分。每次失败时,偏移量都要加倍。