什么是I/O操作,看一下百度百科的说法:I/O操作是指对设备与cpu连接的接口电路的操作,不是对外围设备直接进行操作。宏观上讲,I/O是信息处理系统(例如计算机)与外部世界(可能是人或其他信息处理系统)之间的通信。输入(Input)是系统接收的信号或数据,输出(Output)是从其发送的信号或数据。另一方面,在某一个信息处理系统内部,各部件或组件之间的通信也时刻离不开着I/O。
那什么是文件I/O操作,其实可以理解为程序与文件之间进行数据交换的过程,包括读取和写入文件来实现数据的输入和输出。文件I/O主要涉及打开文件、读取文件内容、写入文件内容和关闭文件等操作。
什么是文件缓冲
将文件内容写入到硬件设备时,比如磁盘的扇区,则需要进行系统调用,这类I/O操作的耗时很长,为了减少I/O操作的次数,文件通常使用缓冲区(当需要写入的字节数不足一个块时,将数据放入缓冲区,当数据凑够一个块的大小后才进行系统调用)。文件的缓存行为,分为全缓冲、行缓冲、无缓冲。
对于磁盘这类的块设备,读写时不是按单个字节进行的,而是按块,每次读写一个块(一般一个块大小4096个字节);如果一个块的大小是4096个字节,则写入一个字节和写入4096个字节,都需要进行一次I/O操作,用时则是相同的。
这个块的大小是和磁盘有关的,不同的磁盘是不一样的。
如果python在驱动信息中找不到一个块的大小(一般不会),那会使用下面这个默认值:
import io
print(io.DEFAULT_BUFFER_SIZE)
# 8192
为了大家都能理解这里先做一下信息科普:
- 系统调用:向操作系统申请一个服务,操作系统响应后,帮助调用硬件的驱动程序,这种操作称为I/O操作
- 磁盘扇区:硬盘的内部圆形金属盘片被磁道划分成若干个扇形区域,这就是硬盘扇区。若干个扇区就组成整个盘片,硬盘的读写以扇区为基本单位。
其实文件缓冲和python没有什么必然联系,这里只是结合python对文件缓冲做一下介绍。
1、全缓冲模式(即I/O操作)
文件数据将根据缓冲区的大小进行收集,然后在缓冲区被填满或手动刷新缓冲区时进行写入操作。这是默认的缓冲模式。
file = open("filename.txt", "w")
2、行缓冲模式(如shell)
在读取或写入文件时,每当遇到换行符时,数据将被刷新到文件中或从缓冲区中读取。可以通过将缓冲区大小设置为1来实现行缓冲模式。
file = open("filename.txt", "w", buffering=1)
3、无缓冲模式(如串口设备)
文件中的数据不会存储在缓冲区中,而是直接通过I/O操作发送或接收。可以通过将缓冲区大小设置为0来实现无缓冲模式。
file = open("filename.txt", "w", buffering=0)
python3打开文件有两种方式,一种是二进制的方式,一种是文本方式。
file1 = open('a.bin', 'wb') #二进制
print(file1) # <_io.BufferedWriter name='a.bin'>
file2 = open('b.txt', 'w') #文本
print(file2) # <_io.TextIOWrapper name='b.txt' mode='w' encoding='cp936'>
print(file2.buffer) # <_io.BufferedWriter name='b.txt'>
我们可以看到,文本模式打开时,里面有一个buffer,这说明文本模式打开时,是基于二进制打开的。下面看一下整体的缓冲模型:
如果TextIO层的缓冲区大小是8192,也就是8192个字节之后,才会输出到Buffer缓冲区里,Buffer中超过4096个字节的时候,才会输出到文件中去。
这里要注意,当你以文本模式打开的时候,输出的是中文,如果utf8编码的话,一个中文是三个字节。
那文件缓冲区的刷新机制是什么:
- 上面介绍了,缓冲区满了的时候,会自动刷新;
- 文件关闭或程序结束的时候,或自动刷新;
- 使用 flush() 手动刷新。