如何使用Unix系统调用打印文本文件的前10行?

时间:2016-07-03 04:59:36

标签: c linux unix

我想编写自己的head Unix命令版本,但我的程序无效。

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

以下是代码:

#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 );
}

我做错了什么?

1 个答案:

答案 0 :(得分:1)

在开始回显第一行之前,打开文件并扫描它以计算总数行是非常奇怪的。在开始回显线之前,完全没有必要事先知道有多少行,它对你没什么用。无论如何,如果你要这样做,那么在重新打开文件之前你应该close()该文件。对于你的简单程序,这是一个良好的形式,而不是正确的功能 - 你观察到的不当行为与此无关。

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

    //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(),并且显然假设每个人都会读取一行。这个假设无效。 read()没有对行终止符进行任何特殊处理,因此您可能具有跨越多行的读取,并且读取只读取部分行(并且可能在同一读取中)。因此,您无法通过计算read()次来计算行数。相反,您必须扫描读缓冲区中的有效字符并计算其中的换行符。

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

  4. 您将缓冲区传递给printf(),好像它是一个以空字符结尾的字符串,但您没有采取任何措施来确保它实际上已终止。 read()不会为您做到这一点。

  5. 我很难相信您声称您的程序始终打印指定文件的所有行,但我相信它会打印您正在测试它的特定文件的所有行。如果文件足够短,整个东西都适合你的缓冲区,它可能会这样做。然后,您的程序可能会在第一次read()调用时将整个内容读入缓冲区(尽管不能保证这样做),然后在每次后续调用时都不读取任何内容,返回-1并保持缓冲区不变。当您最终打印缓冲区时,它仍然包含文件的全部内容。