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

标签 c linux unix

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

我试图打印文本文件的前 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 );
}

我做错了什么?

最佳答案

很奇怪的是,您打开文件并扫描它以计算总行数,然后再继续回显第一行。在开始回显行之前,绝对不需要提前知道总共有多少行,而且它对您没有任何用处。但是,如果您无论如何都要这样做,那么您应该在重新打开文件之前 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(),就好像它是一个以 null 结尾的字符串一样,但您没有采取任何措施来确保它实际上已终止。 read() 不会为您执行此操作。

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

关于c - 如何使用 Unix 系统调用打印文本文件的前 10 行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38166881/

相关文章:

C - 读取 2d int 数组,行以 0 结尾,直到输入结束

c - windows shell中jenkins中linux命令的使用

linux - 内存中的 FUSE 文件系统

c - 从头开始为 Linux 构建 Glibc-2.11.1 时出错

c - C语言:\r or\n?换行符是什么

c - 管理私有(private)堆

linux - 在共享对象中包含静态库?

java - 如何通过UNIX mac终端调试maven项目?

c - 可能的错误 - 将一个流与一个已经有关联的 FD 相关联?

c - 这个 C 程序我做错了什么?