2014-04-13 192 views
1

好了,同時讀取後:How to read a specific line in a text file in C (integers)What is the easiest way to count the newlines in an ASCII file?我想,我可以用在這兩個能夠高效提到的問題並迅速從一個文件讀一行。C:讀取從文件中的特定行,問題

這裏是我的代碼:

char buf[BUFSIZ]; 
intmax_t lines = 2; // when set to zero, reads two extra lines. 
FILE *fp = fopen(filename, "r"); 
while ((fscanf(fp, "%*[^\n]"), fscanf(fp, "%*c")) != EOF) 
{ 

    /* globals.lines_to_feed__queue is the line that we _do_ want to print, 
    that is we want to ignore all lines up to that point: 
    feeding them into "nothingness" */ 

    if (lines == globals.lines_to_feed__queue) 
    { 
    fgets(buf, sizeof buf, fp); 
    } 
    ++lines; 
} 
fprintf(stdout, "%s", buf); 
fclose(fp); 

現在上面的代碼奇妙的作品,我extrememly高興自己搞清楚,你可以fscanf文件達到一定點,然後使用fgets來讀取所有點上的數據到緩衝區,而不是必須每行fgets,然後fprintf buf,當我所關心的是我正在打印的行:我不想存儲字符串,我可以不關心緩衝區,我只打算使用一行

不過,我碰到的,由// when set to zero, reads two extra lines意見指出,唯一的問題:當lines用的0值進行初始化,我要行就像是200,我會得到行會實際上是行202。可能有人請解釋一下我在做什麼錯在這裏/爲什麼發生這種情況,並lines = 2;是否我的速戰速決是罰款,或者如果它是不夠的(如,是一些真正的錯誤會在這裏,它只是偏偏工作)

+0

你喜歡這個fscanf magicry只是做'getc()'並計算'\ n'的任何原因? –

+0

除非'getc()'勝過'fscanf',那麼我有理由爲什麼我應該使用'getc()'? –

回答

3

有兩個原因需要將lines設置爲2,並且這兩個原因都可以從需要第一行的特例中派生。

一方面,在while循環,你要做的第一件事就是用fscanf消耗線,那麼你檢查lines計數器你想要的行相匹配。問題是,如果你想要的線是你剛剛消耗的線,那麼你運氣不好。另一方面,你基本上是通過找到下一個\n並遞增lines你檢查當前行是否是你之後的行。

這兩個因素合起來導致lines計數的偏移量,所以下面是考慮到它們的相同函數的一個版本。此外,一旦找到您正在查找的行,它還包含break;語句,以便while循環停止進一步查看文件。

void read_and_print_line(char * filename, int line) { 
    char buf[BUFFERSIZE]; 
    int lines = 0; 
    FILE *fp = fopen(filename, "r"); 
    do 
    { 
    if (++lines == line) { 
     fgets(buf, sizeof buf, fp); 
     break; 
    } 

    }while((fscanf(fp, "%*[^\n]"), fscanf(fp, "%*c")) != EOF); 
    if(lines == line) 
    printf("%s", buf); 
    fclose(fp); 
} 
+0

+1謝謝,找到你的答案非常豐富和令人滿意的徹底。 –

0

首先,什麼是錯在這裏:這個代碼是無法讀取文件中的第一行(如果globals.lines_to_feed__queue爲0會發生什麼)?如果文件包含連續的換行符,它也會計算錯誤的行數。

其次,你必須認識到沒有魔法。由於您不知道所討論的字符串在哪個偏移處存在,因此您必須耐心地逐個字符地讀取文件,並一路統計字符串結尾。將每個字符的讀/計數委派給fgets/fscanffgetc以進行手動檢查無關緊要 - 無論哪種方式,不感興趣的文件將從磁盤進入OS緩衝區,然後進入用戶空間解釋。

你的直覺是絕對正確的:代碼被破壞。

1

就像看待這個問題的另一種方式......假設你的全球指定1時,第一行是要打印,2第二,等等,那麼:

char buf[BUFSIZ]; 
FILE *fp = fopen(filename, "r"); 
if (fp == 0) 
    return; // Error exit — report error. 

for (int lineno = 1; lineno < globals.lines_to_feed_queue; lineno++) 
{ 
    fscanf(fp, "%*[^\n]"); 
    if (fscanf(fp, "%*c") == EOF) 
     break; 
} 

if (fgets(buf, sizeof(buf), fp) != 0) 
    fprintf(stdout, "%s", buf); 
else 
    …requested line not present in file… 
fclose(fp); 

你可以用fclose(fp);return;代替中斷(如果合適的話)(但確保在退出之前關閉文件;否則會泄漏資源)。

如果您的行數從0開始計數,則將for循環的下限更改爲0

+0

對於「確保在退出之前關閉文件」+1。 –