2016-07-03 46 views
-1

我想写我自己版本的head Unix命令,但是我的程序不工作。如何使用Unix系统调用打印文本文件的前10行?

我试图打印文本文件的前10行,而是程序打印所有行。我通过命令行参数指定要打印的文件名和行数。我只需要使用Unix系统调用,如read(),open()close()

下面是代码:

#include "stdlib.h" 
#include "stdio.h" 
#include <fcntl.h> 
#include <stdlib.h> 
#include <unistd.h> 

#define BUFFERSZ 256 
#define LINES 10 

void fileError(char*, char*); 

int main(int ac, char* args[]) 
{ 
    char buffer[BUFFERSZ]; 
    int linesToRead = LINES; 
    int in_fd, rd_chars; 

    // check for invalid argument count 
    if (ac < 2 || ac > 3) 
    { 
     printf("usage: head FILE [n]\n"); 
     exit(1); 
    } 

    // check for n 
    if (ac == 3) 
     linesToRead = atoi(args[2]); 

    // attempt to open the file 
    if ((in_fd = open(args[1], O_RDONLY)) == -1) 
     fileError("Cannot open ", args[1]); 

    int lineCount = 0; 

    //count no. of lines inside file 
    while (read(in_fd, buffer, 1) == 1) 
    {   
     if (*buffer == '\n') 
     { 
      lineCount++; 
     } 
    } 
    lineCount = lineCount+1; 

    printf("Linecount: %i\n", lineCount); 

    int Starting = 0, xline = 0; 

    // xline = totallines - requiredlines 
    xline = lineCount - linesToRead; 
    printf("xline: %i \n\n",xline); 

    if (xline < 0) 
     xline = 0; 

    // count for no. of line to print 
    int printStop = lineCount - xline; 
    printf("printstop: %i \n\n",printStop); 

    if ((in_fd = open(args[1], O_RDONLY)) == -1) 
     fileError("Cannot open ", args[1]); 

    //read and print till required number 
    while (Starting != printStop) { 
     read(in_fd, buffer, BUFFERSZ); 
     Starting++; //increment starting 
    } 

    //read(in_fd, buffer, BUFFERSZ); 
    printf("%s \n", buffer); 

    if (close(in_fd) == -1) 
     fileError("Error closing files", ""); 
    return 0; 
} 

void fileError(char* s1, char* s2) 
{ 
    fprintf(stderr, "Error: %s ", s1); 
    perror(s2); 
    exit(1); 
} 

我在做什么错?

+0

轻微:为什么在'int main(int ac,char * args [])'中使用'ac,args'而不是常见的'argc,argv'? – chux

+0

查看源代码:https://github.com/goj/coreutils/blob/rm-d/src/head.c – xxfelixxx

+0

在fileError中,对'perror'的调用是错误的。 fprintf可能已经修改了errno,你会得到一个意外的结果。 –

回答

1

打开文件并扫描它以统计总数行,然后再回显第一行,这很奇怪。在开始回显线条之前,完全没有必要提前知道有多少条线条,而且它对您没有任何用处。无论如何,如果你打算这样做的话,那么在你重新打开它之前,你应该知道该文件。对于你的简单程序,这是一个很好的形式,而不是正确的功能 - 你观察到的不当行为与此无关。

有在你的程序中的关键部分几个问题:

//read and print till required number 
    while (Starting != printStop) { 
     read(in_fd, buffer, BUFFERSZ); 
     Starting++; //increment starting 
    } 

    //read(in_fd, buffer, BUFFERSZ); 
    printf("%s \n", buffer); 
  1. 你不检查本节您read()调用的返回值。你必须检查它,因为它不仅告诉你是否有错误/文件结束,而且还有实际读取的字节数。您不能保证在调用任何调用时填充缓冲区,并且只有通过这种方式,您才能知道此后缓冲区的哪些元素包含有效数据。 (在这方面,预计数行对你没有任何帮助。)

  2. 您正在执行原始read() s,并且显然假定每一行都只读一行。这个假设是无效的。 read()没有给出行终止符的任何特殊处理,因此您可能会读取跨越多行的内容,并读取只读取部分行(并且可能在同一次读取中)。因此,您不能通过计算read()调用来计算行数。相反,您必须扫描读缓冲区中的有效字符并计算其中的换行符。

  3. 你实际上并没有在你的读取循环中打印任何东西。相反,你要等到你完成了所有的读取,然后在上次读取之后打印缓冲区中的所有内容。如果在第一次读取时没有获取所需的所有行,那么这将不符合您的目的,因为每次后续的成功读取都会破坏前一次读取的数据。

  4. 您将缓冲区传递给printf()就好像它是一个以空字符结尾的字符串,但是您无法确保它实际上已被终止。 read()不适合你。

我有麻烦相信你的要求,你的程序总是打印指定文件的所有行,但我可以相信,它打印你在测试它的特定文件的所有行。如果文件足够短以至于整个事物都适合你的缓冲区,它可能会这样做。然后你的程序可能会在第一个read()调用中将整个事件读入缓冲区(虽然不能保证这样做),然后在随后的每次调用中不读任何内容,返回-1并保持缓冲区不变。当你最终打印缓冲区时,它仍然包含文件的全部内容。

+1

倒带文件也是一个选项(而不是重新打开它) - 'lseek(fd,0L,SEEK_SET)'会做伎俩,IIRC。 –

+0

@John Bollinger现在你一定已经意识到我是编程C中的新手。我感谢你的输入,但我仍然不确定要修复和更改我的代码,所以我的程序通过打印前10行来正确运行。如果你能帮我修改我的代码,我将不胜感激。 – bmalhi

+0

@bmalhi,我*帮助你。为自己制定细节将对你有好处。 –