1. 程式人生 > >fopen , fread fwrite 函式讀寫二進位制檔案 問題總結

fopen , fread fwrite 函式讀寫二進位制檔案 問題總結

最近在解析 png 資料檔案, 發現一個檔案操作中容易忽略的問題,問題描述如下:

在使用 fread 讀二進位制檔案(png 圖片)的時候, 發現讀取到記憶體中的資料和 二進位制檔案中的資料不一致, 同樣, 在 使用 fwrite 寫二進位制檔案(png 圖片)的時候, 發現寫入到記憶體中的資料和 二進位制檔案中的資料和記憶體中的資料也不一致。 

這個問題頭疼了兩天, 結果發現了一個很低階的錯誤。就是在讀寫二進位制檔案的時候,必須確保檔案的開啟形式是以 二進位制讀寫的形式開啟的, 即:檔案的開啟形式必須是 "rb", "wb" 要不然,讀寫資料的時候,就會出現錯誤。

/*
* 函式說明: 寫二進位制檔案
* 引數描述: _fileName, 檔名稱
*           _buf, 要寫的記憶體緩衝。
*           _bufLen, 記憶體緩衝的長度
*   返回值: 0, 成功
*           -1, 失敗
*
*/


int writeFile(const STR* _fileName, void* _buf, int _bufLen)
{
    FILE * fp = NULL;
    if( NULL == _buf || _bufLen <= 0 ) return (-1);

    fp = fopen(_fileName, "wb"); // 必須確保是以 二進位制寫入的形式開啟

    if( NULL == fp )
    {
        return (-1);
    }

    fwrite(_buf, _bufLen, 1, fp); //二進位制寫

    fclose(fp)
;
    fp = NULL;

    return 0;    
}

/*
 * 函式說明:  
讀二進位制檔案

*  引數描述: _fileName, 檔名稱
*             _buf, 讀出來的資料存放位置
*             _bufLen, 資料的長度資訊
*    返回值:  0, 成功
*             -1, 失敗
*
*/

int readFile(const char* _fileName, void* _buf, int _bufLen)
{
    FILE* fp = NULL;
    if( NULL == _buf || _bufLen <

= 0 ) return (-1);

    fp = fopen(_fileName, "rb"); //
必須確保是以 二進位制讀取的形式開啟
    if( NULL == fp )
    {
        return (-1);
    }

    fread(_buf, _bufLen, 1, fp); // 二進位制讀

    fclose(fp);
    return 0;        
}

函式使用說明: 

FILE * fopen(const char * path,const char * mode);
引數path字串包含欲開啟的檔案路徑及檔名,
引數mode字串則代表著流形態。mode有下列幾種形態字串: 
  r 開啟只讀檔案,該檔案必須存在。 
  r+ 開啟可讀寫的檔案,該檔案必須存在。 
  rb+ 讀寫開啟一個二進位制檔案,只允許讀寫資料。
  rt+ 讀寫開啟一個文字檔案,允許讀和寫。
  w 開啟只寫檔案,若檔案存在則檔案長度清為0,即該檔案內容會消失。若檔案不存在則建立該檔案。 
  w+ 開啟可讀寫檔案,若檔案存在則檔案長度清為零,即該檔案內容會消失。若檔案不存在則建立該檔案。 
  a 以附加的方式開啟只寫檔案。若檔案不存在,則會建立該檔案,如果檔案存在,寫入的資料會被加到檔案尾,即檔案原先的內容會被保留。(EOF符保留) 
  a+ 以附加方式開啟可讀寫的檔案。若檔案不存在,則會建立該檔案,如果檔案存在,寫入的資料會被加到檔案尾後,即檔案原先的內容會被保留。 (原來的EOF符不保留)
  wb 只寫開啟或新建一個二進位制檔案;只允許寫資料。
  wb+ 讀寫開啟或建立一個二進位制檔案,允許讀和寫。
  wt+ 讀寫開啟或著建立一個文字檔案;允許讀寫。
  at+ 讀寫開啟一個文字檔案,允許讀或在文字末追加資料。
  ab+ 讀寫開啟一個二進位制檔案,允許讀或在檔案末追加資料。
  上述的形態字串都可以再加一個b字元,如rb、w+b或ab+等組合,加入b 字元用來告訴函式庫開啟的檔案為二進位制檔案,而非純文字檔案。不過在POSIX系統,包含Linux都會忽略該字元。由fopen()所建立的新檔案會具有S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH(0666)許可權,此檔案許可權也會參考umask 值。 
  有些C編譯系統可能不完全提供所有這些功能,有的C版本不用"r+","w+","a+",而用"rw","wr","ar"等,讀者注意所用系統的規定。
返回值
  檔案順利開啟後,指向該流的檔案指標就會被返回。若果檔案開啟失敗則返回NULL,並把錯誤程式碼存在errno 中
附加說明
  一般而言,開檔案後會作一些檔案讀取或寫入的動作,若開檔案失敗,接下來的讀寫動作也無法順利進行,所以在fopen()後請作錯誤判斷及處理。

fread函式和fwrite函式

1.函式功能

  用來讀寫一個數據塊。

2.一般呼叫形式

  fread(buffer,size,count,fp);

  fwrite(buffer,size,count,fp);

3.說明

  (1)buffer:是一個指標,對fread來說,它是讀入資料的存放地址。對fwrite來說,是要輸出資料的地址。

  (2)size:要讀寫的位元組數;

  (3)count:要進行讀寫多少個size位元組的資料項;

  (4)fp:檔案型指標。