流和缓冲区的概念理解
-
流(stream)
A stream is a source or destination of data that may be associated with a disk or other peripheral.
流(stream)是与磁盘或其它外围设备关联的数据的源或目的地。
Streams are a portable way of reading and writing data. They provide a flexible and efficient means of I/O. A Stream is a file or a physical device (e.g. printer or monitor) which is manipulated with a pointer to the stream.
流是(表达)读写数据的一种可移植的方法,它为一般的I/O操作提供了灵活有效的手段。一个流是一个由指针操作的文件或者是一个物理设备,而这个指针正是指向了这个流。
C语言中stdin、stdout、stderr分别是标准输入流、标准输出流及标准出错流
-
缓冲区(buffer)
缓冲区存在于流与具体的设备终端或者存储介质上的文件之间。
标准I / O提供缓存的目的是尽可能减少使用read和write调用的数量。
它也对每个I / O流自动地进行缓存管理。
标准I / O提供了三种类型的缓存:全缓存、行缓存、无缓存。
(1)全缓存。在这种情况下,当填满标准I / O缓存后才进行实际I / O操作。对于驻在磁盘上的文件通常是由标准I / O库实施全缓存的。在一个流上执行第一次I / O操作时,相关标准I / O函数通常调用malloc获得需使用的缓存。
(2)行缓存。在这种情况下,当在输入和输出中遇到新行符时,标准I / O库执行I / O操作。这允许我们一次输出一个字符(用标准I/O fputc函数),但只有在写了一行之后才进行实际I / O操作。
(3)不带缓存。标准I / O库不对字符进行缓存。如果用标准I / O函数写若干字符到不带缓存
的流中,则相当于用w r i t e系统调用函数将这些字符写至相关联的打开文件上。标准出错流stderr通常是不带缓存的,这就使得出错信息可以尽快显示出来,而不管它们是否含有一个新行字符。ANSI C要求下列缓存特征:
(1) 当且仅当标准输入和标准输出并不涉及交互作用设备时,它们才是全缓存的。
(2) 标准出错决不会是全缓存的。涉及缓冲区的一些问题: gets是一个不推荐使用的函数。问题在于调用者在使用gets时不能指定缓存的长度。这样就可能造成缓存越界(如若该行长于缓存长度),写到缓存之后的存储空间中,从而产生不可予料的后果。
刷新(flush)
缓存可由标准I / O例程自动地刷新(例如当填满一个缓存时),或者可以调用函数ff l u s h刷新一个流。
在U N I X环境中,刷新有两种意思:
-
在标准I / O库方面,刷新意味着将缓存中的内容写到磁盘上(该缓存可以只是局部填写的)
-
在终端驱动程序方面(例如t c f l u s h函数),刷新表示丢弃已存在缓存中的数据。
-
FILE结构体的定义
在C语言中,通过打开流来关联流及其目的地,使用的函数是fopen()
该函数返回一个指向文件的指针(FILE *),该指针包含了足够的可以控制流准确地到达目的地的信息。
将它称为流控制结构体
/* Definition of the control structure for streams */typedef struct {short level; /* fill/empty level of buffer */unsigned flags; /* File status flags */char fd; /* File descriptor */unsigned char hold; /* Ungetc char if no buffer */short bsize; /* Buffer size */unsigned char *buffer; /* Data transfer buffer */unsigned char *curp; /* Current active pointer */unsigned istemp; /* Temporary file indicator */short token; /* Used for validity checking */} FILE; /* This is the FILE object */
mode参数指令
mode参数 | 功能描述 |
---|---|
r | 以只读方式打开文件 |
w | 打开或创建文本文件只写,对已存在的文件清除原内容 |
a | 追加。打开或创建文本文件,在尾部进行写 |
rb | 以只读方式打开二进制文件 |
wb | 打开或创建二进制文件只写,对已存在的文件清除原内容 |
ab | 追加。打开或创建二进制文件,在尾部进行写 |
r+ | 打开文本文件用于更新(读和写) |
w+ | 打开或创建文本文件用于更新,对已存在的文件清除原内容 |
a+ | 追加。打开或创建文本文件用于更新,在尾部进行写 |
r+b或rb+ | 打开二进制文件用于更新 |
w+b或wb+ | 打开或创建二进制文件用于更新,对已存在的文件清除原内容 |
a+b或ab+ | 追加,打开或创建二进制文件更新,在尾部进行写 |
文件操作相关函数
fopen
FILE *fopen(const char *filename, const char *mode)
以mode指定模式打开filename指定的文件,并返回一个与之相关的流。操作失败返回NULL
FILE *fp = fopen('1.txt','r'); //以只读方式打开名为‘1.txt’的文本文件
freopen
FILE *freopen(const char *filename, const char *mode, FILE *stream)
以mode指定模式打开filename指定文件,并将文件关联到stream指定的流中,返回stream
fflush
int fflush(FILE *stream)
像它的名字一样将缓冲区的全部尚未写入文件的数据写入到文件中。错误则返回EOF,否则返回0。
fflush(NULL); //清洗所有的输出流
fclose
int fclose(FILE *stream)
将所有未写入的数据写入stream中,丢弃缓冲区中的所有未读输入数据,并释放自动分配的全部缓冲区,最后关闭流。错误则返回EOF,否则返回0。
remove
int remove(const char *filename)
删除filename指定的文件,后续试图打开该文件的操作将失败。如果删除失败返回非0值。
rename
int rename(const char *oldname,const char* *newname)
修改文件的名字。操作失败返回非0值。
tmpfile
FILE *tmpfile(void)
以模式‘wb+’创建一个临时文件,当该文件被关闭或者程序正常结束时被自动删除。如果创建成功函数返回一个流;如果创建失败则返回NULL。
tmpnam
char tmpnam(char s[L_tmpname])
tmpnam(NULL)函数创建一个与现有文件名都不相同的字符串,并返回一个指向内部静态数组的指针。
tmpnam(s)把创建的字符串保存到数组s中,并把它作为函数值返回;每次调用时生成不同的名字。
setvbuf
int setvbuf(FILE *stream, char *buf, int type, int size)
setvbuf的参数:一个指向流的指针,一个期望缓冲区的地址(buf),缓存的类型(type), 缓存区的字节大小(size)
-
type:
_IOFBF(满缓冲):当缓冲区为空时,从流读入数据。或者当缓冲区满时,向流写入数 据。_IOLBF(行缓冲):每次从流中读入一行数据或向流中写入一行数据。
_IONBF(无缓冲):直接从流中读入数据或直接向流中写入数据,而不设置缓冲区。
如果buf不是NULL,则setvbuf将buf所指向的区域作为缓冲区,否则将分配一个缓冲区。size决定缓冲区的长度。若出错则返回非0值。
setbuf
如果buf的值为NULL,则关闭流stream的缓冲;否则setbuf函数等价于(void)setvbuf(stream,buf,_IOFBF,BUFSIZ);