我想编写自己的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 );
}
我做错了什么?
答案 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);
您不会在本节中检查read()
来电的返回值。您必须检查它,因为它不仅告诉您是否存在错误/文件结尾,还告诉您实际读取了多少字节。您无法保证在任何调用上填充缓冲区,并且只有这样才能知道缓冲区中哪些元素包含有效数据。 (在这方面,预计算线对你没有任何帮助。)
您正在执行原始read()
,并且显然假设每个人都会读取一行。这个假设无效。 read()
没有对行终止符进行任何特殊处理,因此您可能具有跨越多行的读取,并且读取只读取部分行(并且可能在同一读取中)。因此,您无法通过计算read()
次来计算行数。相反,您必须扫描读缓冲区中的有效字符并计算其中的换行符。
您实际上并未在读取循环中打印任何内容。相反,你等到你完成了所有的阅读,然后在最后一次阅读后打印缓冲区的所有内容。如果你没有在第一次读取时获得所需的所有行,那么这将不能满足你的目的,因为每次后续的成功读取都会破坏前一行的数据。
您将缓冲区传递给printf()
,好像它是一个以空字符结尾的字符串,但您没有采取任何措施来确保它实际上已终止。 read()
不会为您做到这一点。
我很难相信您声称您的程序始终打印指定文件的所有行,但我相信它会打印您正在测试它的特定文件的所有行。如果文件足够短,整个东西都适合你的缓冲区,它可能会这样做。然后,您的程序可能会在第一次read()
调用时将整个内容读入缓冲区(尽管不能保证这样做),然后在每次后续调用时都不读取任何内容,返回-1并保持缓冲区不变。当您最终打印缓冲区时,它仍然包含文件的全部内容。