資料流游標


開啟檔案時,會有個游標指向檔案現在的讀取位置,每進行一次讀寫動作,游標會自動往下一個讀取位置前進,可以使用 rewind() 函式將游標重置回檔案開頭,或者是使用 fseek() 函式來移動游標:

int fseek(FILE *fp, long offset, int mode);

offset 是相對於 mode 位置的位移量,可以是正或負數,正數表示往檔案相對於 mode 的下幾筆移動,負數表示往檔案相對於 mode 的上幾筆移動,mode 是巨集定義的數值,可以設置的 mode 巨集名稱如下:

  • SEEK_SET:數值 0,檔案開頭
  • SEEK_CUR:數值 1,目前游標所在位置
  • SEEK_END:數值 2,檔案結尾

要進行非循序的檔案存取,通常會使用二進位模式,並且將資料以一定大小的資料結構包裝起來,下一個主題就會看到,但操作游標對循序性的檔案也有其好處,例如可以在文字檔案中儲存學生的資料並進行查詢,查詢的動作並不一定經過一次,所以可在每次查詢後,將游 標移至檔案首,以便再次查詢,下面這個程式是個簡單的示範:

#include <stdio.h> 

int main(int argc, char* argv[]) {
    FILE *file = fopen("data.txt", "r");

    if(!file) { 
        puts("無法讀取檔案"); 
        return 1; 
    } 

    char name[30]; 
    int request, account, score; 

    puts("輸入選項:");
    puts("1) 顯示所有學生與分數");
    puts("2) 顯示及格學生與分數");
    puts("3) 顯示不及格學生與分數");
    puts("4) 離開");

    while(1) { 
        printf("\n選項? "); 
        scanf("%d", &request); 
        if(request == 4) {
            break; 
        }

        switch(request) { 
            case 1: 
                puts("\n所有學生與分數:");
                break; 
            case 2: 
                puts("\n及格學生與分數:");
                break; 
            case 3: 
                puts("\n不及格學生與分數:");
                break; 
        } 

        fscanf(file, "%d\t%s\t%d", &account, name, &score); 
        while(!feof(file)) { 
            if((request == 1) || (request == 2 && score >= 60) || 
               (request == 3 && score < 60)) {
                printf("%d\t%s\t%d\n", account, name, score);     
            }

            fscanf(file, "%d\t%s\t%d", &account, name, &score); 
        } 

        rewind(file);  // 重置游標,也可使用 fseek(file, 0, SEEK_SET);
    } 

    fclose(file); 

    return 0; 
}

執行結果:

輸入選項: 
1) 顯示所有學生與分數 
2) 顯示及格學生與分數 
3) 顯示不及格學生與分數 
4) 離開

選項? 1 

所有學生與分數: 
1       Justin  90 
2       Momor   90 
3       Bush    75 
4       John    50 
5       Bob     65 
6       Rich    53 
7       Doe     41 
8       Bill    85 
9       Jason   67 
10      Jones   88 

選項? 2 

及格學生與分數: 
1       Justin  90 
2       Momor   90 
3       Bush    75 
5       Bob     65 
8       Bill    85 
9       Jason   67 
10      Jones   88 

選項? 4

為何文字檔案不適合非循序存取,理由很簡單,文字檔案的內容都經過字元轉換,假設現在有個檔案中有兩筆資料如下,其中空白為 '\t'

1       Justin  90 
2       Momor   90 

如果現在更改了第一筆資料如下:

1       caterpillar  90 

則第二筆資料會被覆蓋,如果是在Linux下,換行為'\n',則結果會如下:

1       caterpillar  90or   90 

由於字元轉換後的資料長度並不固定,所以文字檔案並不適合非循序存取。