IO编程中,Stream(流)是一个很重要的概念,可以把流想象成一个水管,数据就是水管里的水,但是只能单向流动。Input Stream就是数据从外面(磁盘、网络)流进内存,Output Stream就是数据从内存流到外面去。
由于CPU和内存的速度远远高于外设的速度,所以,在IO编程中,就存在速度严重不匹配的问题。举个例子来说,比如要把100M的数据写入磁盘,CPU输出100M的数据只需要0.01秒,可是磁盘要接收这100M数据可能需要10秒,怎么办呢?有两种办法:
第一种是CPU等着,也就是程序暂停执行后续代码,等100M的数据在10秒后写入磁盘,再接着往下执行,这种模式称为同步IO;
另一种方法是CPU不等待,只是告诉磁盘,“您老慢慢写,不着急,我接着干别的事去了”,于是,后续代码可以立刻接着执行,这种模式称为异步IO。
异步IO:编程模型复杂、性能高(回调模式、轮询模式)
一、文件读写:
现代操作系统不允许普通的程序直接操作磁盘,所以,读写文件就是请求操作系统打开一个文件对象(通常称为文件描述符),然后,通过操作系统提供的接口从这个文件对象中读取数据(读文件),或者把数据写入这个文件对象(写文件)
1、读文件:
2、文件读写时都有可能产生IOError,一旦出错,后面的f.close()就不会调用。所以,为了保证无论是否出错都能正确地关闭文件,我们可以使用try ... finally
try:
f = open('/path/to/file', 'r')
print(f.read())
finally:
if f:
f.close()
3、Python引入了with语句来自动帮我们调用close()方法
with open('/path/to/file', 'r') as f:
print(f.read())
4、调用read()会一次性读取文件的全部内容,如果文件有10G,内存就爆了,所以,要保险起见,可以反复调用read(size)方法,每次最多读取size个字节的内容。另外,调用readline()可以每次读取一行内容,调用readlines()一次读取所有内容并按行返回list。
for line in f.readlines():
print(line.strip()) # 把末尾的'\n'删掉
5、要读取二进制文件,比如图片、视频等等,用'rb'模式打开文件即可
6、要读取非UTF-8编码的文本文件,需要给open()函数传入encoding参数
7、遇到有些编码不规范的文件,你可能会遇到UnicodeDecodeError,因为在文本文件中可能夹杂了一些非法编码的字符。遇到这种情况,open()函数还接收一个errors参数,表示如果遇到编码错误后如何处理。最简单的方式是直接忽略
f = open('/Users/michael/gbk.txt', 'r', encoding='gbk', errors='ignore')
8、写文件和读文件是一样的,唯一区别是调用open()函数时,传入标识符'w'或者'wb'表示写文本文件或写二进制文件
9、务必要调用f.close()来关闭文件。当我们写文件时,操作系统往往不会立刻把数据写入磁盘,而是放到内存缓存起来,空闲的时候再慢慢写入。只有调用close()方法时,操作系统才保证把没有写入的数据全部写入磁盘。忘记调用close()的后果是数据可能只写了一部分到磁盘,剩下的丢失了。所以,还是用with语句来得保险
with open('/Users/michael/test.txt', 'w') as f:
f.write('Hello, world!')
10、以'w'模式写入文件时,如果文件已存在,会直接覆盖(相当于删掉后新写入一个文件)。如果我们希望追加到文件末尾怎么办?可以传入'a'以追加(append)模式写入
数据读写不一定是文件,也可以在内存中读写
11、StringIO
from io import StringIO
f = StringIO()
f.write('hello')
print(f.getvalue())
12、要读取StringIO,可以用一个str初始化StringIO,然后,像读文件一样读取
13、JSON:
Python内置的json模块提供了非常完善的Python对象到JSON格式的转换
1)序列化:
2)反序列化
3)对象序列化:
很多时候,我们更喜欢用class表示对象,比如定义Student类,然后序列化:
把任意class的实例变为dict:
print(json.dumps(s, default=student2dict))
{"age": 20, "name": "Bob", "score": 88}
要把JSON反序列化为一个Student对象实例,loads()方法首先转换出一个dict对象,然后,我们传入的object_hook函数负责把dict转换为Student实例
def dict2student(d):
return Student(d['name'], d['age'], d['score'])