open, read, write/fopen,fread,fwrite區別



UNIX環境下的C 對二進制流文件的讀寫有兩套班子:1) fopen,fread,fwrite ; 2) open, read, write


在介紹之前先簡單的說一下緩衝區和非緩衝區
1.緩衝文件系統
緩衝文件系統的特點是:在內存開闢一個“緩衝區”,爲程序中的每一個文件使用,當執行讀文件的操作時,從磁盤文件將數據先讀入內存“緩衝區”, 裝滿後再從內存“緩衝區”依此讀入接收的變量。執行寫文件的操作時


,先將數據寫入內存“緩衝區”,待內存“緩衝區”裝滿後再寫入文件。由此可以看出,內存 “緩衝區”的大小,影響着實際操作外存的次數,內存“緩衝區”越大,則操作外存的次數就少,執行速度就快、效率高。一般來


說,文件“緩衝區”的大小隨機器 而定。fopen, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, freopen, fseek, ftell, rewind等


2.非緩衝文件系統
緩衝文件系統是藉助文件結構體指針來對文件進行管理,通過文件指針來對文件進行訪問,既可以讀寫字符、字符串、格式化數據,也可以讀寫二進制數 據。非緩衝文件系統依賴於操作系統,通過操作系統的功能對文件進行


讀寫,是系統級的輸入輸出,它不設文件結構體指針,只能讀寫二進制文件,但效率高、速度 快,由於ANSI標準不再包括非緩衝文件系統,因此建議大家最好不要選擇它。本書只作簡單介紹。open, close, read, write, getc, getchar, putc, putchar 等。

open&&fopen

open 是POSIX 定義的,是系統調用 返回的是文件描述符(int型整數),open系列只能用在 POSIX 的操作系統上。
fopen是ANSIC標準中的C語言庫函數,在不同的系統中應該調用不同的內核api,返回的是一個指向文件結構的指針,fopen系列更具有可移植性


使用open系列函數需要"#include <fcntl.h>" ,鏈接時要之用libc(-lc)
使用fopen系列函數需要"#include <sdtio.h>"


open可以指定權限.
fopen不能指定要創建文件的權限.


open與 read, write 等配合使用, 
fopen與 fread, fwrite等配合使用。


前者無緩衝,後者有緩衝


open每次都需要進行內核態和用戶態的切換;
fopen在用戶態下就有了緩存,在進行read和write的時候減少了用戶態和內核態的切換,
表現爲,如果順序訪問文件,fopen系列的函數要比直接調用open系列快;如果隨機訪問文件open要比fopen快。


open屬於低級IO,fopen是高級IO。由於能更多地與操作系統打交道,open系列可以訪問更改一些fopen系列無法訪問的信息,如查看文件的讀寫權限,這些額外的功能通常因系統而異。


文件描述符是linux下的一個概念,linux下的一切設備都是以文件的形式操作.如網絡套接字、管道、硬件設備等。當然包括操作文件。
設備文件不可以當成流式文件來用,只能用open
fopen是用來操縱正規文件的,並且設有緩衝的,跟open還是有一些區別
一般用fopen打開普通文件,用open打開設備文件




用法舉例:
函數名: fopen 
功  能: 打開一個流 
用  法: FILE *fopen(char *filename, char *type); 
程序例:
#include <stdlib.h> 
#include <stdio.h> 
#include <dir.h>
int main(void) 

    char *s; 
    char drive[MAXDRIVE]; 
    char dir[MAXDIR]; 
    char file[MAXFILE]; 
    char ext[MAXEXT]; 
    int flags;
    s=getenv("COMSPEC"); /* get the comspec environment parameter */ 
    flags=fnsplit(s,drive,dir,file,ext);
    printf("Command processor info:\n"); 
    if(flags & DRIVE) 
       printf("\tdrive: %s\n",drive); 
    if(flags & DIRECTORY) 
       printf("\tdirectory: %s\n",dir); 
    if(flags & FILENAME) 
       printf("\tfile: %s\n",file); 
    if(flags & EXTENSION) 
       printf("\textension: %s\n",ext);
    return 0; 

函數名: open 
功  能: 打開一個文件用於讀或寫 
用  法: int open(char *pathname, int access[, int permiss]); 
程序例:
#include <string.h> 
#include <stdio.h> 
#include <fcntl.h> 
#include <io.h>
int main(void) 

   int handle; 
   char msg[] = "Hello world";
   if ((handle = open("TEST.$$$", O_CREAT | O_TEXT)) == -1) 
   { 
      perror("Error:"); 
      return 1; 
   } 
   write(handle, msg, strlen(msg)); 
   close(handle); 
   return 0; 
}


read/write和fread/fwrite區別

read在linux/unix中讀二進制與普通文件沒有區別.
fread可以讀一個結構.


read是帶了緩存但是指的是系統層或者說kernel層,當然也可能不帶,比如直接DMA,由驅動決定。
fread帶緩存指的是應用層帶緩存,


read是內核的緩衝。
fread是標準庫的緩衝,


read/write如果可以精確控制一次讀寫的數據,則會比fread/fwrite更加高效


read/write對應Linux中的system call, 而fread/fwrite則可以說是對read/write的又一次封裝,read/write更加原生,如果不考慮跨平臺,建議多使用read/write.


read函數從打開的設備或文件中讀取數據。
#include <unistd.h>  ssize_t read(int fd, void *buf, size_t count); 返回值:成功返回讀取的字節數,出錯返回-1並設置errno,如果在調read之前已到達文件末尾,則這次read返回0
參數count是請求讀取的字節數,讀上來的數據保存在緩衝區buf中,同時文件的當前讀寫位置向後移。注意這個讀寫位置和使用C標準I/O庫時的讀寫位置有可能不同,這個讀寫位置是記在內核中的,而使用C標準I/O庫時的讀


寫位置是用戶空間I/O緩衝區中的位置。


fread就是通過read來實現的,fread是C語言的庫,而read是系統調用
但是差別在read每次讀的數據是調用者要求的大小,比如調用要求讀取10個字節數據,read就會讀10個字節數據到數組中,而fread不一樣,爲了加快讀的速度,fread每次都會讀比要求更多的數據,然後放到緩衝區中,這樣


下次再讀數據只需要到緩衝區中去取就可以了。


如果文件的大小是8k。
你如果用read/write,且只分配了2k的緩存,則要將此文件讀出需要做4次系統調用來實際從磁盤上讀出。
如果你用fread/fwrite,則系統自動分配緩存,則讀出此文件只要一次系統調用從磁盤上讀出。
也就是用read/write要讀4次磁盤,而用fread/fwrite則只要讀1次磁盤。效率比read/write要高4倍。
如果程序對內存有限制,則用read/write比較好。
都用fread 和fwrite,它自動分配緩存,速度會很快,比自己來做要簡單。如果要處理一些特殊的描述符,用read 和write,如套接口,管道之類的
系統調用write的效率取決於你buf的大小和你要寫入的總數量,如果buf太小,你進入內核空間的次數大增,效率就低下。而fwrite會替你做緩存,減少了實際出現的系統調用,所以效率比較高。
如果只調用一次(可能嗎?),這倆差不多,嚴格來說write要快一點點(因爲實際上fwrite最後還是用了write做真正的寫入文件系統工作),但是這其中的差別無所謂。
============ 


舉個例子:


做如下步驟的操作:


打開文件
讀文件的0k~4k(read or fread)
其他操作
讀文件的1k~3k(read or fread)
關閉文件
這時候如果是read,步驟4要調用內核;而如果是fread,因步驟2在應用層已經緩衝所需內容,數據會直接返回,無需再次調用內核

fread每次會讀取一個緩衝區大小的數據,32位下一般是4096個字節,相當於調用了read(fd,buf,4096)

比如需要讀取512個字節數據,分4次讀取,
調用read就是:
for(i=0; i<4; ++i)
read(fd,buf,128)
一共有4次系統調用


而fread一次就讀取了4096字節放到緩衝區了,所以省事了
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章