C语言 流缓冲
**From : https://www.gnu.org/software/libc/manual/html_node/Stream-Buffering.html**
12.20 流缓冲
通常情况下,写入流的字符会在写入前进行累积然后以块的形式异步转送而非由应用程序马上输出。相似的,流通常从主机环境以块的形式而非字节-字节的形式读入数据。这称为缓冲。
如果你正在写一个用流来交互的程序,当你设计交互接口时你需要理解缓冲是如何工作的。否则,你可能会发现输出(例如进程提示信息)不输出理想值,或者出现奇怪的行为。
这一节讲解的是在流/文件/设备之间传输设备,并不会涉及echoing, flow control, 特殊设备。如果想了解关于终端设备的通用控制操作符的信息,参考Low-Level Terminal Interface。
你可以通过使用底层I/O函数与文件描述符来来避免使用流缓冲。参考 Low-Level I/O。
12.20.1 概念与术语
一共有三种缓冲策略:(译者注:缓冲策略是写入流/文件的充分条件,不是必要的。缓冲区存在的意义就是在使用“Stream-level I/O”时从缓冲区进行异步块写入/读出,这样可以在设备堵塞的时候加快效率。如果一次只写入少量数据,内核一看没有堵塞,“干脆”就把缓冲区的内容写入了,反正放着也是放着)
- 无缓冲 unbuffered :从一个无缓冲的流中读写会马上产生效果
- 行缓冲 line buffered:当遇到一个换行符的时候字符会以块的形式读写。
- 满缓冲 fully buffered:字符会以任意大小的块写入读出。(真的是直译。。感觉和网上一些说满的时候才读写的说法不一样,说明可能是不堵塞的时候就读写缓冲区,最多等到缓冲区满)
新开的流一般是满缓冲的,只有一个例外:当流是一个可交互设备(例如终端)的时候,流将变为行缓冲。如果想了解关于如何选择缓冲策略,参考 Controlling Buffering 。通常情况下,默认会选择出最方便的缓冲策略。
在行缓冲下,以换行符结束的信息会马上输出到交互设备里——这通常是你想要的。不以换行符结尾的信息可能不会马上显示到交互设备,所以如果你想要立即显示,你需要在写入后使用fflush
, 参考 Flushing Buffers.(译者注:通常使用fprintf+stderr,因为stderr默认是无缓冲的)
12.20.2 清除缓冲区
清除缓冲区意味着立即以块的形式写入缓冲区内收集的内容。有很多情况下缓冲区会自动清除:
- 当输出缓冲区满后尝试输出。
- 当流关闭的时候。参考 Closing Streams。
- 当程序通过调用
exit
结束的时候。参考 Normal Termination。 - 当向行缓冲缓冲区写入换行符时。
- 当从本文件的任意流读入时。
If you want to flush the buffered output at another time, call fflush
, which is declared in the header file stdio.h.如果你想要在别的时候清除缓冲区,可以使用stdio.h中声明的fflush
。
- Function: int fflush (FILE *stream)
Preliminary: | MT-Safe | AS-Unsafe corrupt | AC-Unsafe lock corrupt | See POSIX Safety Concepts.这个函数会导致与stream关联的缓冲区被写入到文件中,如果stream是一个空指针,那么fflush
会导致目前打开的所有流的缓冲区被清除。这个函数将返回EOF
如果发生一个写入错误,否则返回0。
- Function: int fflush_unlocked (FILE *stream)
Preliminary: | MT-Safe race:stream | AS-Unsafe corrupt | AC-Unsafe corrupt | See POSIX Safety Concepts. fflush_unlocked
函数和fflush
相同,除了它不会隐式的锁上这个stream流。
此处省略一些...
- Function: void **_flushlbf** (void)
Preliminary: | MT-Safe | AS-Unsafe corrupt | AC-Unsafe lock corrupt | See POSIX Safety Concepts.该函数会清除所有的行缓冲流的缓冲区,声明在stdio_ext.h头文件中。
兼容性: 有一些脑子坏掉的操作系统总是对那些以换行符为导向的输入“念念不忘”——清除一个行缓冲会导致一个换行符被写入。幸运的是,这个特性越来越少见,并且对于GNU C Library 你不用担心。
有一些情况下不去手动清除缓冲区而是忘记这件事可能是一个更好的选择,因为读写可能不是必要的而且是相对花费大的。
- Function: void **__fpurge** (FILE *stream)
Preliminary: | MT-Safe race:stream | AS-Unsafe corrupt | AC-Unsafe corrupt | See POSIX Safety Concepts.__fpurge
函数会把stream流的缓冲区清空,但是不会产生读写!声明在stdio_ext.h。
12.20.3 控制缓冲策略
在打开一个流之后,你通过使用setvbuf
选择该流使用何种缓冲策略。
以下列出的函数和宏在头文件stdio.h中声明。
- Function: int setvbuf (FILE *stream, char buf, int mode, size_t size)*
Preliminary: | MT-Safe | AS-Unsafe corrupt | AC-Unsafe lock corrupt | See POSIX Safety Concepts.这个函数是用来定义stream流该采用何种缓冲策略——可以是 _IOFBF
(满缓冲), _IOLBF
(行缓冲), or _IONBF
(无缓冲)。如果你输入的一个空指针作为buf参数,那么setvbuf
会自动使用malloc
申请一块内存,当你关闭流的时候,缓冲区会被清除释放掉。否则buf对应的内存块至少应该是size大小。你不应该释放掉buf对应的空间只要流还没有关闭。你应该确保buf对应的内存是静态存储的(例如使用malloc
)。使用一个自动存储期限的buf块不是一个好的选择——除非在退出当前块之前关掉了流。当buf对应的数组块是缓冲区的时候,stream流i/o函数会使用这个内存块作为一些内部用途——所以你不应该试着去直接访问这个数组的值当它被使用的时候。 setvbuf
成功时返回0,否则返回非零数当mode是不可取的或者要求不能被满足。
- Macro: int **_IOFBF**
这个宏的值是一个整数常量表达式,可以被setvbuf
函数用来是缓冲区是满缓冲的。
- Macro: int **_IOLBF**
这个宏的值是一个整数常量表达式,可以被setvbuf
函数用来是缓冲区是行缓冲的。
- Macro: int **_IONBF**
这个宏的值是一个整数常量表达式,可以被setvbuf
函数用来是缓冲区是无缓冲的。
- Macro: int BUFSIZ
这个宏的值是一个整数常量表达式,可以被setvbuf
函数用来表达size,这个值被保证最小是256。 BUFSIZ
是由操作系统选择的,以此来提高i/o的效率。所以使用 BUFSIZ
作为setvbuf
的大小值是一个很好的选择。事实上,你可以用过fstat
系统调用获得一个更好的值(在文件属性的 st_blksize
区域),参考 Attribute Meanings.有时候人们使用 BUFSIZ
作为申请内存空间的大小值(或者作为i/o操作的内存,例如fgets)——这没什么特别的理由,除了能提高一些i/o效率。
- Function: void setbuf (FILE *stream, char buf)*
Preliminary: | MT-Safe | AS-Unsafe corrupt | AC-Unsafe lock corrupt | See POSIX Safety Concepts.If buf is a null pointer, the effect of this function is equivalent to calling setvbuf
with a mode argument of_IONBF
. Otherwise, it is equivalent to calling setvbuf
with buf, and a mode of _IOFBF
and a size argument of BUFSIZ
.The setbuf
function is provided for compatibility with old code; use setvbuf
in all new programs.如果buf是一个空指针,这个函数的效果等于setvbuf
使用_IONBF
.否则,等效于使用 setvbuf
和 _IOFBF
BUFSIZ
这两个参数。该函数是为了兼容一些老的代码,在新的程序中请使用setvbuf
.
- Function: void setbuffer (FILE *stream, char buf, size_t size)*
Preliminary: | MT-Safe | AS-Unsafe corrupt | AC-Unsafe lock corrupt | See POSIX Safety Concepts.
省略...这个函数是为了兼容一些BSD的老旧代码。请使用setvbuf
.
- Function: void setlinebuf (FILE *stream)
Preliminary: | MT-Safe | AS-Unsafe corrupt | AC-Unsafe lock corrupt | See POSIX Safety Concepts.
省略...这个函数是为了兼容一些BSD的老旧代码。请使用setvbuf
.
剩下一些不常用的函数就不翻译了。
C语言 流缓冲的更多相关文章
- C语言 流缓冲 Stream Buffering
From : https://www.gnu.org/software/libc/manual/html_node/Stream-Buffering.html 译者:李秋豪 12.20 流缓冲 通常情 ...
- c++流缓冲学习---rdbuf()
我们使用STL编程的时候有时候会想到把一个流对象指向的内容用另一个流对象来输出,比如想把一个文件的内容输出到显示器上,我们可以用简单的两行代码就可以完成: ifstream infile(" ...
- Java基础知识强化之IO流笔记41:字符流缓冲流之复制文本文件案例02(使用 [ newLine() / readLine() ] )(重要)
1. 使用字符流缓冲流的特殊功能 [ newLine() / readLine() ] 需求:把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中 数据源: a.txt -- 读取数据 ...
- Java基础知识强化之IO流笔记39:字符流缓冲流之复制文本文件案例01
1. 字符流缓冲流之复制文本文件案例 需求:把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中 数据源: a.txt -- 读取数据 -- 字符转换流 -- InputStreamRe ...
- Java基础知识强化之IO流笔记38:字符流缓冲流之BufferedWriter / BufferedReader使用
1. 字符流缓冲流: 字符流为了高效读写,也提供了对应的字符缓冲流. BufferedWriter:字符缓冲输出流 BufferedReader:字符缓冲输入流 2. BufferedWriter使用 ...
- (19)IO流之字符流FileReader和FileWriter,缓冲字符流---缓冲输入字符流BufferedReader和缓冲输出字符流BufferedWriter
字符流,读取的文件是字符的时候,有两个基类一个是Reader,一个是Writer这有点拟人的感觉,人直接看懂的是文字 字符流 字节流:读取的是文件中的二进制字节流并不会帮你转换成看的懂得字符 字符流: ...
- -1-4 java io java流 常用流 分类 File类 文件 字节流 字符流 缓冲流 内存操作流 合并序列流
File类 •文件和目录路径名的抽象表示形式 构造方法 •public File(String pathname) •public File(String parent,Stringchild) ...
- IO流(字节流,字符流,缓冲流)
一:IO流的分类(组织架构) 根据处理数据类型的不同分为:字节流和字符流 根据数据流向不同分为:输入流和输出流 这么庞大的体系里面,常用的就那么几个,我们把它们抽取出来,如下图: 二:字符字节 ...
- java基础46 IO流技术(输出字符流/缓冲输出字符流)
一.输出字符流 1.1.输出字符流体系 --------| Writer:输出字符流的基类(抽象类) ----------| FileWriter:向文件输出数据输出字符流(把程序中的数据写到硬盘中 ...
随机推荐
- mysql添加外键约束变为索引
今天有位自己填上一坑:mysql储存引擎 原因就是数据库表引擎为:MyISAM,建立主外键关系需要是InnoDB: 解决方案:alter table table_name1 engine=inno ...
- PHP初入,for循环使用
一: 找出100-999之间的所有"水仙花数".所谓水仙花数是指一个三位 数,各位数字的立方和等于该数本身.(如153次方=1的3次方+5的3次方+3的3次方)并输出这些数字 想想 ...
- web切图的几个快捷键及总结
自由的控制视图系列 自由的浏览图片:按住空格后,鼠标拖动 自由的缩放图片:按住alt+滚轮 切换到实际像素(100%):Ctrl + 1 工作区类型切换:Tab 控制内容系列 通过画面上点选一个图 ...
- 201521123091 《Java程序设计》第4周学习总结
Java 第二周总结 第四周的作业. 目录 1.本章学习总结 2.Java Q&A 3.使用码云管理Java代码 4.PTA实验 1.本章学习总结 1.1 尝试使用思维导图总结有关继承的知识点 ...
- 201521123037 《Java程序设计》第5周学习总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 1.2 可选:使用常规方法总结其他上课内容. 接口: 接口简而言之是方法声明和常量值的集合,接口中所有的方法默认为public ...
- 201521123005《java程序设计》第五周学习总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 1.2 可选:使用常规方法总结其他上课内容. 接口 有点类似继承中父类与子类的关系 方法声明和常量值的集合 对行为的抽象 一种 ...
- 201521123060 《Java程序设计》第4周学习总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 1.object是所有类的父类: 2.继承的作用:抽取共同特征,复用代码: 3.设计类的继承 ...
- Python[小甲鱼007了不起的分支和循环]
加载背景音乐播放背景音乐(设置单曲循环)我方飞机诞生interval = 0while True:if 用户是否点击关闭按钮退出程序breakinterval += 1if interval = 50 ...
- 201521123108 《Java程序设计》第11周学习总结
1. 本周学习总结 2. 书面作业 本次PTA作业题集多线程 Q1.互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问) 1.1 除了使用synchronized修饰方法实现互斥同步访问 ...
- Git 查看/修改用户名、邮箱
用户名和邮箱地址的作用 用户名和邮箱地址是本地Git客户端的一个变量,不随git库而改变. 每次commit都会用用户名和邮箱纪录. github的contributions统计就是按邮箱来统计的. ...