2015-01-20 114 views
0

我的程序需要從二進制文件讀取鏈接列表,這個函數做得很好,併爲它分配正確的內存,但由於某種原因,它在斷開之前做了另一個循環。嘗試尋找一個好的解決方案,沒有運氣,鏈表中的最後一個結構變得垃圾。二進制文件的EOF是什麼?

的結構:

typedef struct 
{ 
    char id[10]; 
    char * first_name; 
    char * last_name; 
    int age; 
    char gender; 
    char * username; 
    char * password; 
    char * description; 
    int hobbies[4]; 
    struct Person * next_client; 
}Person; 

這裏是一些代碼:

Person * input_from_file(Person * member) 
{ 
int str_size; 
Person * clients_start = NULL; 
FILE * filePointerRead; 

filePointerRead = fopen("input.bin", "rb"); 

if (filePointerRead != NULL){ 
    while (1){ 

     member = NULL; 
     member = (Person*)malloc(sizeof(Person)); 

     fread(&member->id, sizeof(char), ID_DIGITS + 1, filePointerRead); 

     fread(&str_size, sizeof(int), 1, filePointerRead); 
     member->first_name = (char*)malloc(str_size*sizeof(char)); 
     fread(member->first_name, sizeof(char), str_size, filePointerRead); 

     //more reading from file 

     member->next_client = NULL; 
     clients_start = receive_clients_info(clients_start, member); //function to put the received struct from file to end of the linked list 

     if (feof(filePointerRead)) 
      break; 
    } 
    fclose(filePointerRead); 
} 
return clients_start; 
} 
+0

也許你輸入的文件包含一些額外的數據,你不期待?一個額外的字節足以打破邏輯。 – 2015-01-20 22:52:00

+1

'fread'有一個返回值的原因。 – 2015-01-20 22:52:32

+0

[如何使用EOF運行C中的文本文件?]的可能重複(http://stackoverflow.com/questions/1835986/how-to-use-eof-to-run-through-a-text- file-in-c) – gsamaras 2015-01-20 22:52:59

回答

2

與調用feof的問題是,它不會回你一個「真正的」,除非你試圖讀時你在EOF。換句話說,如果您的文件剛好有100個字節,並且您已成功嘗試完全讀取100個字節,則feof將返回「false」,直到您嘗試再讀取至少一個字節。

這就是爲什麼你應該避免feof贊成檢查fread的返回值,它告訴你的原因多少字節已經從文件中讀取:

if (fread(&member->id, sizeof(char), ID_DIGITS + 1, filePointerRead) != ID_DIGITS + 1) { 
    // The code above knows that sizeof(char) is always 1. 
    // For other data types you need to compute the actual size 
    // by multiplying sizeof(T) by the number of items that you read. 
    break; 
} 

做相同的所有地方,你請致電fread

!=作品,因爲fread總是返回您傳遞的時候纔可以完成請求的確切大小比較:

成功完成後,fread()應返回的元素個數成功讀取小於nitems只如果遇到讀取錯誤或文件結束。

+0

是否可以像fseek和ftell那樣在櫃檯上保存文件的大小,然後在ftell達到計數器時放置斷點? – 2015-01-20 23:39:14

+0

@SashaG這當然也是可能的。但是,檢查每個「fread」,如果在文件讀取過程中發生「中途飛行」,就會更容易發現錯誤。 – dasblinkenlight 2015-01-21 00:45:20

2

檢查的fread()代替foef(),也有對堆棧溢出有關,feof()返回true多的答案時,EOF指標設置,fread()將在讀取文件結尾時設置它。

fread()將返回比當到達文件的末尾,但你的程序需要一個額外的循環,其中fread()試圖讀到文件的末尾,它將設置EOF指標所要求的字節0以下。

看到這個「while(!feof(file))」 is always wrong

1

您遇到的問題是,直到文件的EOF標誌被設置,feof()才返回true,並且文件的EOF標誌沒有被設置,直到嘗試讀取文件失敗,因爲在那裏沒有數據留在文件中讀取。

這裏是一個例子:假設文件中有1個字節,並且你有一個循環,一次讀取一個字節的文件。

通過循環第一次讀取一個字節並返回給程序。如果程序測試feof(),它將仍然返回FALSE,因爲讀取文件成功。

第二次通過循環,文件中的所有字節都已經被讀取,所以0個字節被讀取並返回到程序,此時EOF標誌被設置,因爲讀取文件由於達到結束。此時feof()將返回TRUE。

在我的例子中,即使文件中只有一個字節,你也經歷了兩次循環。你的代碼也一樣。

要解決此問題,請始終檢查fread()調用的結果。它返回讀取的項目數(不是字節數)。順便說一句,fread()將始終讀取整個項目,永遠不會讀取部分項目。如果fread()返回的項目數量少於預期值,請跳出循環。通常情況下,你會跳出循環,因爲你已經到達文件末尾,但有可能出現其他錯誤 - 也許有人將電源線拉到外部硬盤驅動器。如果你想知道爲什麼fread()沒有讀取任何內容,可以使用feof()或者ferror()。

0
any easy way to accomplish the task is: 

calculating the total length of each complete record in the file 
(from your code, I assume all records are the same length) 
fopen(..inputfile..) 
if fopen not successful, 
then 
    perror() 
    exit(EXIT_FAILURE); 
endif 

// implied else, fopen successful 

while(completelength == fread(the complete length into a local buffer)) 
{ 
    ...extract each field from local buffer into struct... 
    ...place struct into linked list... 
} 

//when get here, reading/building linked list is done 
fclose(inputfile) 
...