2016-07-03 86 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,我*幫助你。爲自己制定細節將對你有好處。 –