程序代碼的依賴和調用關係以下圖所示:
c++
區分用戶態和內核態主要是因爲系統資源的有限性,不能無限制的隨意分配給用戶使用,必須由系統進行統一管理程序員
內核爲用戶提供了統一的API供其使用,不一樣的系統的API接口不一樣,爲了便於代碼的移植,出臺了POSIX標準,類Unix系統(Unix、Linux、BSD、SunOS等)均支持該標準。vim
問題:
由上圖咱們可看到,每執行一次系統調用,都要涉及到CPU狀態的切換,即從用戶態切換到內核態,即從用戶空間切換到內核空間,實現上下文切換的過程,會消耗至關一部分的CPU資源,所以頻繁的磁盤訪問對程序的執行效率將形成很大影響。數組
解決方案:
爲了解決以上的難題,採用了緩衝區
的概念,當對磁盤文件進行操做時,可一次性從磁盤文件中讀出大量的數據暫放到緩衝區中,之後對這部分數據的訪問就不須要再進行系統調用了;當對文件行操做後,可將處理後的數據暫存到輸出緩衝區,待文件緩衝區滿後,一次性寫入到磁盤。ide
以上,數據的輸入輸出就像是水在流動同樣,所以咱們採用了流
的概念。函數
文件流 :
簡單來講就是創建在面向對象基礎上的一種抽象的處理數據的工具。在流中,定義了一些處理數據的基本操做,如讀取數據,寫入數據等,程序員是對流進行全部操做的,而不用關心流的另外一頭數據的真正流向;
文件流用結構體表示:struct FILE
.
FILE的結構體又是怎麼樣的呢?咱們能夠進行查找一下:工具
[niesh@niesh ~]$ vim /usr/include/stdio.h
咱們看到了 stdio.h
的文件中有一行:操作系統
__BEGIN_NAMESPACE_STD /* The opaque type of streams. This is the definition used elsewhere. */ typedef struct _IO_FILE FILE; __END_NAMESPACE_STD
顯然,FILE
是 _IO_FILE
的類型替換,那麼咱們找一下 _IO_FILE
在哪裏呢?指針
[niesh@niesh ~]$ grep -rn "\<_IO_FILE\>" /usr/include/ /usr/include/c++/4.8.2/streambuf:178: * This is based on _IO_FILE, just reordered to be more consistent, /usr/include/libio.h:145:struct _IO_jump_t; struct _IO_FILE; /usr/include/libio.h:163: struct _IO_FILE *_sbuf; /usr/include/libio.h:246:struct _IO_FILE { //此處正解 /usr/include/libio.h:267: struct _IO_FILE *_chain; /usr/include/libio.h:291: struct _IO_FILE _file; /usr/include/libio.h:299: struct _IO_FILE *_freeres_list; /usr/include/libio.h:316:typedef struct _IO_FILE _IO_FILE; /usr/include/libio.h:325:#define _IO_stdin ((_IO_FILE*)(&_IO_2_1_stdin_)) /usr/include/libio.h:326:#define _IO_stdout ((_IO_FILE*)(&_IO_2_1_stdout_)) /usr/include/libio.h:327:#define _IO_stderr ((_IO_FILE*)(&_IO_2_1_stderr_)) /usr/include/libio.h:329:extern _IO_FILE *_IO_stdin attribute_hidden; /usr/include/libio.h:330:extern _IO_FILE *_IO_stdout attribute_hidden; /usr/include/libio.h:331:extern _IO_FILE *_IO_stderr attribute_hidden; /usr/include/libio.h:391:extern int __underflow (_IO_FILE *); /usr/include/libio.h:392:extern int __uflow (_IO_FILE *); /usr/include/libio.h:393:extern int __overflow (_IO_FILE *, int); /usr/include/libio.h:395:extern _IO_wint_t __wunderflow (_IO_FILE *); /usr/include/libio.h:396:extern _IO_wint_t __wuflow (_IO_FILE *); /usr/include/libio.h:397:extern _IO_wint_t __woverflow (_IO_FILE *, _IO_wint_t); /usr/include/libio.h:435:extern int _IO_getc (_IO_FILE *__fp); /usr/include/libio.h:436:extern int _IO_putc (int __c, _IO_FILE *__fp); /usr/include/libio.h:437:extern int _IO_feof (_IO_FILE *__fp) __THROW; /usr/include/libio.h:438:extern int _IO_ferror (_IO_FILE *__fp) __THROW; /usr/include/libio.h:440:extern int _IO_peekc_locked (_IO_FILE *__fp); /usr/include/libio.h:446:extern void _IO_flockfile (_IO_FILE *) __THROW; /usr/include/libio.h:447:extern void _IO_funlockfile (_IO_FILE *) __THROW; /usr/include/libio.h:448:extern int _IO_ftrylockfile (_IO_FILE *) __THROW; /usr/include/libio.h:465:extern int _IO_vfscanf (_IO_FILE * __restrict, const char * __restrict, /usr/include/libio.h:467:extern int _IO_vfprintf (_IO_FILE *__restrict, const char *__restrict, /usr/include/libio.h:469:extern _IO_ssize_t _IO_padn (_IO_FILE *, int, _IO_ssize_t); /usr/include/libio.h:470:extern _IO_size_t _IO_sgetn (_IO_FILE *, void *, _IO_size_t); /usr/include/libio.h:472:extern _IO_off64_t _IO_seekoff (_IO_FILE *, _IO_off64_t, int, int); /usr/include/libio.h:473:extern _IO_off64_t _IO_seekpos (_IO_FILE *, _IO_off64_t, int); /usr/include/libio.h:475:extern void _IO_free_backup_area (_IO_FILE *) __THROW; /usr/include/libio.h:478:extern _IO_wint_t _IO_getwc (_IO_FILE *__fp); /usr/include/libio.h:479:extern _IO_wint_t _IO_putwc (wchar_t __wc, _IO_FILE *__fp); /usr/include/libio.h:480:extern int _IO_fwide (_IO_FILE *__fp, int __mode) __THROW; /usr/include/libio.h:514:extern int _IO_vfwscanf (_IO_FILE * __restrict, const wchar_t * __restrict, /usr/include/libio.h:516:extern int _IO_vfwprintf (_IO_FILE *__restrict, const wchar_t *__restrict, /usr/include/libio.h:518:extern _IO_ssize_t _IO_wpadn (_IO_FILE *, wint_t, _IO_ssize_t); /usr/include/libio.h:519:extern void _IO_free_wbackup_area (_IO_FILE *) __THROW; /usr/include/stdio.h:44:struct _IO_FILE; /usr/include/stdio.h:48:typedef struct _IO_FILE FILE; /usr/include/stdio.h:64:typedef struct _IO_FILE __FILE; /usr/include/stdio.h:168:extern struct _IO_FILE *stdin; /* Standard input stream. */ /usr/include/stdio.h:169:extern struct _IO_FILE *stdout; /* Standard output stream. */ /usr/include/stdio.h:170:extern struct _IO_FILE *stderr; /* Standard error output stream. */
(⊙o⊙)…,還挺多啊,不過仔細觀察,發現只有 libio.h
的246行是對該結構體的定義,咱們打開瞅瞅!rest
[niesh@niesh ~]$ vim /usr/include/libio.h
struct FILE
的結構體成員以下代碼所示:
struct _IO_FILE { int _flags; /* High-order word is _IO_MAGIC; rest is flags. */ #define _IO_file_flags _flags /* The following pointers correspond to the C++ streambuf protocol. */ /* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */ char* _IO_read_ptr; /* Current read pointer */ char* _IO_read_end; /* End of get area. */ char* _IO_read_base; /* Start of putback+get area. */ char* _IO_write_base; /* Start of put area. */ char* _IO_write_ptr; /* Current put pointer. */ char* _IO_write_end; /* End of put area. */ char* _IO_buf_base; /* Start of reserve area. */ char* _IO_buf_end; /* End of reserve area. */ /* The following fields are used to support backing up and undo. */ char *_IO_save_base; /* Pointer to start of non-current get area. */ char *_IO_backup_base; /* Pointer to first valid character of backup area */ char *_IO_save_end; /* Pointer to end of non-current get area. */ struct _IO_marker *_markers; struct _IO_FILE *_chain; int _fileno; #if 0 int _blksize; #else int _flags2; #endif _IO_off_t _old_offset; /* This used to be _offset but it's too small. */ #define __HAVE_COLUMN /* temporary */ /* 1+column number of pbase(); 0 is unknown. */ unsigned short _cur_column; signed char _vtable_offset; char _shortbuf[1]; /* char* _save_gptr; char* _save_egptr; */ _IO_lock_t *_lock; #ifdef _IO_USE_OLD_IO_FILE };
文件描述符:
每一個進程,當打開一個文件後,內核會爲其創建一個打開文件的數組 (數組的前三個爲stdin,stdout,stderr),而後返回打開文件位於數組的索引值(下標),該因此只即爲文件描述符,只要文件不關閉,用戶即可以根據該描述符對文件進行訪問和操做。
不一樣點:
文件描述符:表示爲int類型的對象:如stdin對應文件描述符0,stdout對應文件描述符1;
流:表示爲指向結構FILE的指針FILE* ,所以流也稱爲文件指針
若須要對特定設備進行控制操做,必須使用文件描述符方式,沒有函數能對流進行這類操做
若是須要按照特殊的方式進行I/O操做(例如非阻塞的方式),必須使用文件描述符方式,也沒有函數能對流進行這類操做。
聯繫: 流給用戶程序提供了更高一級的(功能更強大,使用更簡化)的I/O接口,它處在文件描述符方式的上層,也就是說,流函數是經過文件描述符函數來實現的。