程序代码的依赖和调用关系以下图所示:
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接口,它处在文件描述符方式的上层,也就是说,流函数是经过文件描述符函数来实现的。