1. 概述
标准I/O库由ISO C标准说明,其与POSIX定义的文件I/O具有明显区别。标准I/O库是围绕流进行的,而POSIX定义的文件I/O则是针对文件描述符的。
2. 缓冲区
标准I/O 会对用户的I/O操作进行缓冲,共分为全缓冲、行缓冲及不缓冲三种。
全缓冲:直到用户定义的缓冲区被填满,才会调用系统I/O函数。
行缓冲:在缓冲区(一般大小为1024)被填满或者遇到换行符'/n’时才调用系统I/O函数
无缓冲:没有缓冲区,立即调用系统I/O函数。
ISO C要求下列缓冲特征:
a. 当且仅当标准输入和标准输出并不涉及交互作用设备时,它们才是全缓存的。
b. 标准出错决不会是全缓冲的
但是,这并没有告诉我们如果标准输入和输出涉及交互作用设备时,它们是不带缓存的还是行缓存的,以及标准输出是不带缓存的,还是行缓存的。
很多系统默认使用下列类型的缓冲:
a. 标准出错是不带缓冲的。
b. 如若是涉及终端设备的其他流,则它们是行缓冲的;否则是全缓冲的。
需要注意的是,这里的缓冲区是指用户空间的缓冲区。我们常常说系统调用read、write、open、close是unbuffered I/O,但是,write的底层也可以分配内核缓冲区。
3. FILE结构体
标准I/O 通过fopen会返回一个指向FILE的指针,FILE结构内容如下:
1: typedef struct _IO_FILE FILE;
2:
3: struct _IO_FILE {
4: int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
5: #define _IO_file_flags _flags
6:
7: /* The following pointers correspond to the C++ streambuf protocol. */
8: /* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
9: char* _IO_read_ptr; /* Current read pointer */
10: char* _IO_read_end; /* End of get area. */
11: char* _IO_read_base; /* Start of putback+get area. */
12: char* _IO_write_base; /* Start of put area. */
13: char* _IO_write_ptr; /* Current put pointer. */
14: char* _IO_write_end; /* End of put area. */
15: char* _IO_buf_base; /* Start of reserve area. */
16: char* _IO_buf_end; /* End of reserve area. */
17: /* The following fields are used to support backing up and undo. */
18: char *_IO_save_base; /* Pointer to start of non-current get area. */
19: char *_IO_backup_base; /* Pointer to first valid character of backup area */
20: char *_IO_save_end; /* Pointer to end of non-current get area. */
21:
22: struct _IO_marker *_markers;
23:
24: struct _IO_FILE *_chain;
25: int _fileno;
26: #if 0
27: int _blksize;
28: #else
29: int _flags2;
30: #endif
31: _IO_off_t _old_offset; /* This used to be _offset but it's too small. */
32:
33: #define __HAVE_COLUMN /* temporary */
34: /* 1+column number of pbase(); 0 is unknown. */
35: unsigned short _cur_column;
36: signed char _vtable_offset;
37: char _shortbuf[1];
38:
39: /* char* _save_gptr; char* _save_egptr; */
40:
41: _IO_lock_t *_lock;
42: #ifdef _IO_USE_OLD_IO_FILE
43: };
标准库函数都是通过对FILE的操作来实现读写文件的目的。
4. 标准输入、标准输出和标准出错
对进程,系统预定义了上述三个流,并且这三个流可以自动地被进程使用,这三个流通过预定义文件指针:stdin、stdout、stderr加以引用。
我们可以查看其缓冲区属性,程序如下:
1: //输出FILE属性
2: void streaming_property(FILE* file)
3: {
4: //输出FILE缓冲区类型
5: if(file->_flags & _IO_UNBUFFERED)
6: printf("unbuffered/n");
7: else if(file->_flags & _IO_LINE_BUF)
8: printf("line-buffered/n");
9: else
10: printf("fully-buffered/n");
11:
12: //输出缓冲区大小
13: printf("buffer size is %d/n", file->_IO_buf_end -
14: file->_IO_buf_base);
15:
16: //输出discriptor值
17: printf("discriptor is %d/n/n", fileno(file));
18: }
19:
20:
21: int main(int argc, char** argv)
22: {
23: printf("stdin is ");
24: streaming_property(stdin);
25:
26: printf("stdout is ");
27: streaming_property(stdout);
28:
29: printf("stderr is ");
30: streaming_property(stderr);
31: }
输出:
1: stdin is fully-buffered
2: buffer size is 0
3: discriptor is 0
4:
5: stdout is line-buffered
6: buffer size is 1024
7: discriptor is 1
8:
9: stderr is unbuffered
10: buffer size is 0
11: discriptor is 2
5. 常用的标准库函数
更改缓冲类型:setbuf/setvbuf
流的打开和关闭: fopen/fclose
单字符输入: getc/fgetc/getchar
流的错误处理: ferror/feof/clearerr
返还字符: ungetc
单字符输出: putc/fputc/putchar
行输入: gets/fgets
行输出: puts/fputs
二进制读写: fwrite/fread
流的定位: ftell/fseek/rewind/fgetpos/fsetpos
格式化输出: printf/fprintf/sprintf
格式化输入: scanf/fscanf/sscanf
参考文献
1. apue第二版
2. http://hi.chinaunix.net/?uid-20693307-action-viewspace-itemid-46724