5.2更新順序文件

   許多系統中的標準輸入/輸出庫都允許程序打開一個文件,同時進行寫入和讀出的操作:

  

  1. FILE *fp; 
  2. fp = fopen(file, "r+"); 

上面的例子代碼打開了文件名由變量file指定的文件,對於存取權限的設定表明程序希望對這個文件進行輸入和輸出操作。

  編程者也許認爲,程序一旦執行上述操作完畢,就可以自由地交錯進行讀出和寫入操作。遺憾的是,事實總難隨人所願,爲了保持與過去不能同時進行讀寫操作的程序的向下兼容性,一個輸入操作不能隨後直接跟一個輸出操作,反之亦然。如果要同時進行輸入和輸出操作,必須在其中插入fseek函數的調用。

  下面的程序片段似乎更新了一個順序文件中的記錄:

 

  1. FILE *fp; 
  2. struct record rec; 
  3. ... 
  4.  
  5. while (fread((char *)&rec, sizeof(rec), 1, fp) == 1) { 
  6.     //對rec執行某些操作 
  7.     if (/* rec必須被重新寫入*/ ) { 
  8.         fseek(fp, -(long)sizeof(rec), 1); 
  9.         fwrite( ( char *) rec, sizeof(rec), 1, fp); 
  10.     } 

  這段代碼看上去毫無問題:&rec在傳入fread和fwrite函數時被小心翼翼地轉換爲字符指針類型,sizeof(rec)被轉換爲長整型(fseek函數要求第二個參數是long類型,因爲int類型的整數可能無法包含一個文件的大小;sizeof返回一個unsigned值,因此首先必須將其轉換爲有符號類型纔有可能將其反號)。但是這段代碼仍然可能運行失敗,而且出錯的方式非常難於察覺。

  問題出在:如果一個記錄需要被重新寫入文件,也就是說,fwrite函數得到執行,對這個文件執行的下一個操作將是循環開始的fread函數。因爲在fwrite函數調用與fread函數調用之間缺少了一個fseek函數調用,所有無法進行上述操作。解決的辦法是把這段代碼改寫爲:

  1. while (fread( ( char *)&rec, sizeof(rec), 1, fp) == 1) { 
  2.     /* 對rec執行某些操作*/ 
  3.     if (/* rec 必須被重新寫入 */) { 
  4.         fseek(fp, -(long)sizeof(rec), 1); 
  5.         fwrite((char *)&rec, sizeof(rec), 1, fp); 
  6.         fseek(fp, 0L, 1); 
  7.     } 

  第二個fseek函數雖然看上去什麼也沒做,但它改變了文件的狀態,使得文件現在可以正常地進行讀取了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章