C語言中文網 目錄

fread和fwrite函數,C語言fread和fwrite函數詳解

對文件格式化讀寫函數 fprintf 與 fscanf 而言,盡管它可以從磁盤文件中讀寫任何類型的文件,即讀寫的文件類型可以是文本文件、二進制文件,也可以是其他形式的文件。但是,對二進制文件的讀寫來說,考慮到文件的讀寫效率等原因,還是建議盡量使用 fread 和 fwrite 函數進行讀寫操作。

fread 與 fwrite 函數的原型如下面的代碼所示:

size_t fread(void *buf, size_t size, size_t count, FILE *fp);
size_t fwrite(const void * buf, size_t size, size_t count, FILE *fp);

在上面的 fread 和 fwrite 函數原型中:
  • 參數 size 是指單個元素的大小(其單位是字節而不是位,例如,讀取一個 int 型數據就是 4 字節);
  • 參數 count 指出要讀或寫的元素個數,這些元素在 buf 所指的內存空間中連續存放,共占“size*count”個字節。

即 fread 函數從文件 fp 中讀出“size*count”個字節保存到 buf 中,而 fwrite 把 buf 中的“size*count”個字節寫到文件 fp 中。最后,函數 fread 和 fwrite 的返回值為讀或寫的記錄數,成功時返回的記錄數等于 count 參數,出錯或讀到文件末尾時返回的記錄數小于 count,也可能返回 0。

需要注意的是,盡管 fread 和 fwrite 函數可以對數據進行成塊讀寫,但并不是說一次想讀寫多少數據就能全部讀寫多少數據,畢竟緩存有限,而且不同的操作系統的緩存大小也可能不一樣。同時,許多程序員還認為函數的參數 (size、count) 與位置對齊有關,甚至認為語句“fwrite(ptr,1,1024,fp)”的執行效率會比“fwrite(ptr,1024,1,fp)”高。實際情況并非如此,如在 glibc-2.17 庫中對 fwrite 函數的實現如下:
_IO_size_t _IO_fwrite (const void *buf, _IO_size_t size, _IO_size_t count, _IO_FILE *fp)
{
    _IO_size_t request = size * count;
    _IO_size_t written = 0;
    CHECK_FILE (fp, 0);
    if (request == 0)
        return 0;
    _IO_acquire_lock (fp);
    if (_IO_vtable_offset (fp) != 0 || _IO_fwide (fp, -1) == -1)
        written = _IO_sputn (fp, (const char *0 buf, request);
    _IO_release_lock (fp);
    if (written == request)
        return count;
    else if (written == EOF)
        return 0;
    else
        return written / size;
}
從上面的 fwrite 函數源碼實現中可以清楚地看到:

首先,在把參數 size 與 count 傳進函數之后,第一步就是通過語句“_IO_size_t request=size*count;”來計算“size*count”,所以這兩個參數與什么位置對齊根本沒有半點關系。

其次,在函數返回時,如果整個寫入成功(“written==request”),就返回 count;如果遇到 EOF(“written==EOF”),就返回 0;否則返回“written/size”。由此可見,函數返回的是成功寫入的塊數,而不是字節數(除非 size 為 1),這樣做有許多好處。例如,在寫入多個結構體時,返回值能告訴你成功寫入的結構體的個數。當然,這樣看來,前面的“fwrite(ptr,1,1024,fp)”與“fwrite(ptr,1024,1,fp)”語句還是有所差別的。但是,如果調用者只關心是否全部寫入成功,那么就完全沒必要糾結于語句“fwrite(ptr,1,1024,fp)”與“fwrite(ptr,1024,1,fp)”之間的差別了。

對于 fread 函數,其道理與 fwrite 函數完全一樣,如下面的函數源代碼所示:
_IO_size_t _IO_fread (void *buf,_IO_size_t size,_IO_size_t count,_IO_FILE *fp)
{
    _IO_size_t bytes_requested = size * count;
    _IO_size_t bytes_read;
    CHECK_FILE (fp, 0);
    if (bytes_requested == 0)
        return 0;
    _IO_acquire_lock (fp);
    bytes_read = _IO_sgetn (fp, (char *) buf, bytes_requested);
    _IO_release_lock (fp);
    return bytes_requested == bytes_read ? count : bytes_read / size;
}
除此之外,函數 fwrite 還與文件的打開模式有關。例如,如果文件的打開模式是“w+”,則是從文件指針指向的地址開始寫,替換掉之后的內容,文件的長度可以不變,fp 的位置移動 count 個數;如果文件的打開模式為“a+”,則從文件的末尾開始添加,文件的長度會不斷增加。

精美而實用的網站,提供C語言C++STLLinuxShellJavaGo語言等教程,以及socketGCCviSwing設計模式JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo