我想编写自己版本的 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);
在此部分中,您无需检查
read()
调用的返回值。您必须检查它,因为它不仅告诉您是否存在错误/文件结束,还告诉您实际读取了多少字节。不保证您在任何调用时都会填充缓冲区,只有这样您才能知道随后缓冲区的哪些元素包含有效数据。 (在这方面,预计数行对您没有任何帮助。)您正在执行原始的
read()
,并且显然假设每个都只会读取一行。这个假设是无效的。 read() 不会对行终止符进行任何特殊处理,因此您可能会进行跨多行的读取,以及仅读取部分行的读取(可能两者都在同一次读取中)。因此,您无法通过计算read()
调用来计算行数。相反,您必须扫描读取缓冲区中的有效字符并计算其中的换行符。您实际上并没有在读取循环中打印任何内容。相反,您等到完成所有读取后,然后在上次读取后打印缓冲区中的所有内容。当您在第一次读取中没有获得所需的所有行时,这将无法达到您的目的,因为后续的每次成功读取都会破坏前一个读取中的数据。
您将缓冲区传递给
printf()
,就好像它是一个以 null 结尾的字符串一样,但您没有采取任何措施来确保它实际上已终止。read()
不会为您执行此操作。
我很难相信你的说法,即你的程序总是打印指定文件的所有行,但我可以相信它会打印你正在测试的特定文件的所有行。如果文件足够短,整个文件都适合您的缓冲区,那么它可能会这样做。然后,您的程序可能会在第一次 read()
调用时将整个内容读入缓冲区(尽管不能保证这样做),然后在每次后续调用中不读取任何内容,返回 -1 并离开缓冲区不变。当您最终打印缓冲区时,它仍然包含文件的全部内容。
关于c - 如何使用 Unix 系统调用打印文本文件的前 10 行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38166881/