2017-05-29 50 views
8

我有,我想沒有處理迭代中任何形式的當前行的文件已知直線。我正在尋找的是確定文本文件的最佳方式。例如,將當前行存儲到變量中似乎毫無用處,直到達到預定行。C:最好的方式去一個文件

例子:

file.txt的

foo 
fooo 
fo 
here 

通常情況下,爲了得到here,我會做這樣的:

FILE* file = fopen("file.txt", "r"); 
if (file == NULL) 
    perror("Error when opening file "); 
char currentLine[100]; 
while(fgets(currentLine, 100, file)) 
{ 
    if(strstr(currentLine, "here") != NULL) 
     return currentLine; 
} 

fgets將要讀完全沒有用的三條線和currentLine將不得不存儲foo,fooofo

有沒有更好的方式來做到這一點,知道here是4號線?有點像go to但文件?

+2

對於普通文件,做更好的唯一途徑是建立和維護自己的指數行號和fseek偏移量。 (這很簡單,但有點工作。) –

回答

5

您無法直接訪問到一個文本文件中的給定線(除非所有線具有在字節相同的尺寸;以及用UTF8 everywhere Unicode字符可採取可變字節數,1至6;以及在大多數情況下行具有不同的長度 - 從一條線不同到下一個)。所以你不能使用fseek(因爲你事先不知道文件偏移量)。

但是(至少在Linux系統),線與\n(換行符)結束。所以,你可以通過字節讀取字節數數看:

int c= EOF; 
int linecount=1; 
while ((c=fgetc(file)) != EOF) { 
    if (c=='\n') 
    linecount++; 
} 

然後你不需要存儲整個行。

所以,你可以到達線#45這種方式(使用while ((c=fgetc(file)) != EOF) && linecount<45) ...),然後才用fgets或POSIX系統(見this例子)更好,但getline(3)讀整行。請注意,fgetsgetline的實現可能會建立在fgetc之上,或者至少與它共享一些代碼。請記住,<stdio.h>緩衝 I/O,請參閱setvbuf(3)和相關功能。


另一種方法是在兩遍中讀取文件。第一遍將一些有效的數據結構(向量,散列表,樹......)中的每一行開始的偏移量(使用ftell(3) ...)存儲起來。第二遍使用該數據結構來檢索(行開始的)偏移量,然後使用fseek(3)(使用該偏移量)。


第三種方式,POSIX具體的,將是使用mmap(2)文件內存映射到你的virtual address space(這非常適用於不太大的文件,例如小於幾千兆字節)。隨着護理(您可能需要mmap一個額外的最終頁,以確保數據是零字節結束),那麼你將能夠使用strchr(3)'\n'

PS。順便說一句,線的概念(和行尾標記)因操作系統而異。在Linux上,最後一行是\n字符。在Windows線路上傳聞以\r\n等結尾......

+1

在技術上,在Windows上,行也以'\ n'字符結束......它們之前只有一個'\ r'。關鍵是,計數'\ n's也可以在Windows上運行。 –

+0

是否有利用字符而不是逐行迭代字符的優點? – Badda

+1

@Badda:你將如何逐行迭代? –

8

既然你不知道每一行的長度,沒有,你將不得不通過之前的線。

如果你知道每一行的長度,你很可能有多少字節移動文件指針玩。你可以用fseek()來做到這一點。

1

如果你不知道每條線的長度,你必須要經過他們。但是,如果你知道行,你想停下來,你可以這樣做:

while (!found && fgets(line, sizeof line, file) != NULL) /* read a line */ 
{ 
    if (count == lineNumber) 
    { 
     //you arrived at the line 
     //in case of a return first close the file with "fclose(file);" 
     found = true; 
    } 
    else 
    { 
     count++; 
    } 
} 

至少可以避開那麼多的電話strstr

5

A FILE * C中是一個流char s。在一個可搜索的文件中,您可以使用fseek()的文件指針來解決這些char。但除此之外,文件中沒有「特殊字符」,換行符只是另一個正常字符。

因此,簡而言之,不,您不能直接跳轉到文本文件的一行,只要您事先不知道行的長度。

C中的這個模型對應於典型操作系統提供的文件。如果你仔細想想,要知道各行的起點,你的文件系統必須在某處存儲這些信息。這將意味着專門處理文本文件。

什麼你可以也不過只是計數的線條,而不是模式匹配,這樣的事情:

#include <stdio.h> 

int main(void) 
{ 
    char linebuf[1024]; 
    FILE *input = fopen("seekline.c", "r"); 
    int lineno = 0; 
    char *line; 
    while (line = fgets(linebuf, 1024, input)) 
    { 
     ++lineno; 
     if (lineno == 4) 
     { 
      fputs("4: ", stdout); 
      fputs(line, stdout); 
      break; 
     } 
    } 
    fclose(input); 
    return 0; 
} 
相關問題