- 涉及数据交换,通常是磁盘、网络等,就需要IO接口。
- IO编程中,Stream(流)是一个很重要的概念。
- CPU和内存的速度远高于外设速度,在IO编程中,存在速度严重不匹配的问题。
- 同步IO:程序暂停执行后续代码,等数据写入磁盘,再往下执行。
- 异步IO:CPU不等待,后续代码立刻接着执行。回调模式,轮询模式。
文件读写
- 读写文件:请求操作系统打开一个文件对象(通常称为文件描述符)
- 通过操作系统提供的接口从这个文件对象中读取/写入数据(读/写文件)。
读文件
- 内置
open()
,传入文件名和标示符。文件不存在,会抛出一个IOError
的错误。 - 调用
read()
方法可一次读取文件全部内容,把内容读到内存,用一个str
对象表示。 - 调用
close()
方法关闭文件。 - 文件使用完毕后必须关闭,占用操作系统资源,且同一时间打开数量有限。
with
语句自动调用close()
方法
with open('/path/to/file', 'r') as f:
print(f.read())
- 文件很小:
read()
一次性读取最方便;不能确定文件大小:反复调用read(size)
比较保险。 readline()
每次读取一行内容。- 配置文件,调用
readlines()
一次读取所有内容并按行返回list
。
file-like Object
open()
返回有read()
方法的对象,统称为file-like Object。- 可以是内存的字节流,网络流,自定义流等;不要求从特定类继承,只要写个
read()
方法。 StringIO
:在内存中创建的file-like Object,常用作临时缓冲。
二进制文件
字符编码
- 读取非UTF-8编码的文本文件,需要给
open()
传入encoding
参数。 - 有些编码不规范文件可能会
UnicodeDecodeError
,文本文件中可能夹杂一些非法编码字符。 open()
接收errors
参数,如遇到编码错误后可直接忽略。errors=
'ignore'
写文件
- 标识符
'w'
或者'wb',
写文本文件或写二进制文件。 - 调用
write()
方法
来写入文件,调用close()
方法
来关闭文件。 'w'
模式写入文件时,如果文件已存在,会直接覆盖;'a'
以追加(append)模式写入。
StringIO和BytesIO
# 创建一个StringIO
from io import StringIO
f = StringIO()
f.write('hello')
f.write(' ')
f.write('world!')
# getvalue()方法用于获得写入后的str
print(f.getvalue()) # hello world!
# 可以用一个str初始化StringIO
from io import StringIO
f = StringIO('Hello!\nHi!\nGoodbye!')
while True:
s = f.readline()
if s == '':
break
print(s.strip())
BytesIO
操作文件和目录
import os
os.name # 操作系统类型
# 'posix':系统是Linux、Unix或Mac OS X;'nt':Windows系统
# 获取详细的系统信息
os.uname()
# uname()Windows不提供
环境变量
- 操作系统中定义的环境变量,全部保存在
os.environ
这个变量 - 要获取某个环境变量的值,可以调用
os.environ.get('key')
。
操作文件和目录
# 操作文件和目录的函数一部分在os模块,一部分在os.path模块
import os
# 查看、创建和删除目录
# 查看当前目录的绝对路径:
os.path.abspath('.') # '/Users/michael'
# 在某个目录下创建一个新目录,首先把新目录的完整路径表示出来:
os.path.join('/Users/michael', 'testdir') # '/Users/michael/testdir'
# 然后创建一个目录:
os.mkdir('/Users/michael/testdir')
# 删掉一个目录:
os.rmdir('/Users/michael/testdir')
# 合成路径时,不要直接拼字符串,通过os.path.join(),可正确处理不同操作系统的路径分隔符。
# 拆分路径时,不要直接拆字符串,通过os.path.split(),可把路径拆分为两部分
# 后一部分:最后级别的目录或文件名
os.path.split('/Users/michael/testdir/file.txt') # ('/Users/michael/testdir', 'file.txt')
# os.path.splitext()可直接得到文件扩展名
os.path.splitext('/path/to/file.txt') # ('/path/to/file', '.txt')
# 对文件重命名:
os.rename('test.txt', 'test.py')
# 删掉文件:
os.remove('test.py')
# 列出当前目录下的所有目录
[x for x in os.listdir('.') if os.path.isdir(x)]
# 列出所有的.py文件
[x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py']
序列化
- 把变量从内存中变成可存储或传输的过程称之为序列化。pickling
- 把变量内容从序列化的对象重新读到内存里称之为反序列化。unpickling
pickle
模块来实现序列化。
# 把一个对象序列化并写入文件
import pickle
d = dict(name='Bob', age=20, score=88)
pickle.dumps(d) # b'\x80\x03}q\x00(X\x03\x00\x00\x00ageq\...'
# 对象序列化后写入一个file-like Object
f = open('dump.txt', 'wb')
pickle.dump(d, f)
f.close()
# 可把内容读到一个bytes,用pickle.loads()方法反序列化出对象。
# 可直接用pickle.load()方法从一个file-like Object中直接反序列化出对象。
f = open('dump.txt', 'rb')
d = pickle.load(f)
f.close()
d # {'age': 20, 'score': 88, 'name': 'Bob'}
JSON
- 在不同的编程语言之间传递对象,须把对象序列化为标准格式,比如XML。
- 序列化为JSON,表示出来是字符串,可被所有语言读取,也可存储到磁盘/通过网络传输。
- JSON不仅是标准格式,且比XML更快,而且可以直接在Web页面中读取。
JSON类型 | Python类型 |
---|
{} | dict |
[] | list |
"string" | str |
1234.56 | int或float |
true/false | True/False |
null | None |
- 内置
json
模块提供Python对象到JSON格式的转换。
import json
d = dict(name='Bob', age=20, score=88)
json.dumps(d) # '{"age": 20, "score": 88, "name": "Bob"}'
- 把JSON反序列化为Python对象。
loads()
把JSON的字符串反序列化。load()
方法从file-like Object
中读取字符串并反序列化。
json_str = '{"age": 20, "score": 88, "name": "Bob"}'
json.loads(json_str) # {'age': 20, 'score': 88, 'name': 'Bob'}
JSON进阶
dumps()
方法参数列表,第一个必须的obj
参数,还提供了可选参数,定制JSON序列化。- 可选参数
default
把任意一个对象变成一个可序列为JSON的对象。
# default可把任意一个对象变成一个可序列为JSON的对象。
# 为Student专门写一个转换函数,再把函数传进去。
def student2dict(std):
return {
'name': std.name,
'age': std.age,
'score': std.score
}
# Student实例首先被student2dict()函数转换成dict,然后再被顺利序列化为JSON
print(json.dumps(s, default=student2dict)) # {"age": 20, "name": "Bob", "score": 88}
- 可把任意
class
的实例变为dict,__dict__属性
# 把任意class的实例变为dict
print(json.dumps(s, default=lambda obj: obj.__dict__))
# 通常class的实例都有一个__dict__属性,它就是一个dict,用来存储实例变量。
# 少数例外,比如定义了__slots__的class。
- JSON反序列化为一个
类
对象实例 loads()
方法转换出一个dict
对象,传入object_hook
函数把dict
转换为类
实例
def dict2student(d):
return Student(d['name'], d['age'], d['score'])
json_str = '{"age": 20, "score": 88, "name": "Bob"}'
print(json.loads(json_str, object_hook=dict2student))
# <__main__.Student object at 0x10cd3c190>