美好的中秋,朋友圈在享受悠闲周末的时候,刚入门 Python 的程序员小R在公司埋头加班,不知时间几何,一不小心把下周的工作捯饬完了,心情愉悦,不能自拔。
这不,周一的早上,小R吹着口哨,泡着枸杞,幻想着划水到飞起,嘴角抑制不住的咧到了耳朵根儿,翘起了二郎腿。
正抖腿抖到舒坦的时候,微信收到了一条消息,点开一看,消息来自一个熟悉又陌生的名字,在记忆的排水沟里使劲掏了掏,好不容易对号入座。一个许久未曾联系的同学小K,消息只有两个字:
“在吗?”
看着这两个字, 小R眉头一皱,发现事情
怎么回事?他这是要干嘛?为什么要问在吗?
是要借钱嘛?是要结婚嘛?是要...
挣扎良久,小R放下了二郎腿,按下了键盘:
“在”
此时心里已经在自导自演各种应对场景:
“要是借钱,我就...”
“要是结婚,我就...”
“....”
有一条消息过来,在它闪动的第24 次小R打开了聊天窗口:“听说你是 Python 大佬,我有一个问题想问你。”
嘿,吓死我了,你早说啊,此时小R内心一阵窃喜:“哎呀,我这么低调,竟然被人发现大佬的身份啦,看来我还要再低调一点,哈哈哈哈哈哈...”
低调的小R低调的在窗口敲下了如下内容:
“哎呀,没有啦,你有什么问题,随便问,没有我不会的。”
enter 一键发送。
小K:“太好了,Python 里面怎么设置文件的缓冲啊?”
小R:“....”
文件我懂,缓冲我懂,怎么设置,我哪知道怎么设置...
小K:“还在吗?”
好想说不在,当然认真负责的小R当然不会这样,有句伟大的“名言”怎么说的来着:自己的低调,跪着也要低调完...
于是,小R默默的打开了 Google...
00.文件的缓冲
如何设置文件的缓冲,先要知道什么是文件的缓冲:
当我们将文件内容写入到硬件设备的时候,我们需要系统调用(系统调用也就是向操作系统申请一个服务,操作系统响应以后,帮助我们调用硬件的驱动程序)来完成写操作,这类操作我们也就是 I/O 操作。I/O 操作很耗时,为了提高效率,我们就要减少 I/O 操作的次数,我们使用的手段就是为文件设置一个缓冲区。
对于磁盘这种块设备,它的读写不是一个一个的字节,而是按“块”。假设一个“块”的大小是 4096 个字节,你写入一个字节,或者写入 4096 个字节,都需要一次 I/O 操作,设置缓冲区,当写入的数据不足一个“块”大小时,都放入到缓冲区当中,等凑够了一个“块”的数据量,再调用一次 I/O 操作,这样达到减少 I/O 操作的目的。
01.Python中文件对象的缓冲行为
文件的缓冲一般分为“全缓冲”、“行缓冲”、“无缓冲”。
“全缓冲”就是我在上面说的,缓冲区有一定大小,数据凑齐了这个大小就进行一次系统调用;“行缓冲”是在某些终端设备中上使用,碰到换行符进行一次系统调用;“无缓冲”是在一些不希望进行缓冲的设备上,比如串口设备,我们就需要及时把数据发送到串口上去。
下面我们就来看一下,在 Python 中默认的文件对象缓冲行为是怎样的。
首先我们创建一个 test.txt 的文件,以“只写”的形式打开:
f = open('test.txt','w')
然后我们来观察一下文件中的内容(此时应该为空):
接下来我们向 test.txt 中写入一些内容:
f = open('test.txt','w')
f.write('abc')
我们再来看一下文件中的内容:
仍然没有输出,这就意味着 “abc” 并没有真实的写入到磁盘中,而是进入到了缓冲区,其实到这你可以探测一下缓冲区的大小,通常一个“块”的大小为 4096 个字节,你可以尝试写入来试验,直到 tail -f test.txt 有内容显示为止。
这就是普通文件默认的缓冲行为,缓冲区的大小是根据平台和自身的属性相关的。在某些时候,我们需要改变缓冲区的大小,该怎么做呢?
其实很好解决:在 open 函数中,有个 buffering 参数,可以让这个问题迎刃而解。
我们将 buffering 设置为大于 1 的整数 n(n 为缓冲区的大小),这就是“全缓冲”;将 buffering 设置为 1,这就是“行缓冲”;将 buffering 设置为 0,这就是“无缓冲”。
接下来我们就尝试一下:
f = open('test1.txt','w',buffering=1024)
f.write('*'*512)
我们用同样的“只读”方式创建 test1.txt,设定缓冲区大小为 1024,我们先写入 512 个 “*”,接下来看一下文件的内容:
接下来我们就凑齐 1024 个字节:
f = open('test1.txt','w',buffering=1024)
f.write('*'*512)
f.write('*'*511)
f.write('/')
此时文件的内容为:
这就全部输出出来了。
同理,对于“行缓冲”和“无缓冲”也是类似的操作,改变相应 buffering 的值即可,只是对于“行缓冲”,记得要写入换行符的时候才会在文件中显示出内容,感兴趣的可以尝试一下。