本系列是学习 廖雪峰 Python3 教程 过程中记录的笔记,本篇文章记录 Python
中的 I/O
编程,主要内容有文件的读写、内存的读写、对文件及目录的操作,以及两种常见的序列化操作。
I/O 编程
- 基本概念:
input
,output
,stream
; - 存在问题:输入和接收速度不匹配;
- 解决方法:同步(等待
I/O
的执行结果)、异步(回调–好了叫我,轮询—好了没…好了没); - 收获新知:编程语言都会把操作系统提供的低级C接口封装起来方便使用;
文件读写
-
with open
的方式代码更加简洁,该方法会自动调用f.close()
; -
f.read()
会一次性读取文件的全部内容,如果不确定文件大小,建议反复调用f.read(size)
,每次最多读取size
个字节;with open('/path/to/file', 'r') as f: print(f.read())
-
对于二进制文件,打开的模式为
rb
; -
对于非
UTF-8
的文件,需要传入encoding
参数; -
对于编码不规范的文件,可能会遇到非法编码的字符,最简单的处理方式是直接忽略;
with open('/Users/michael/gbk.txt', 'r', encoding='gbk', errors='ignore') as f: print(f.read())
-
写文件:常用标识符
w
直写(会覆盖原文件的内容)、wb
直写二进制文件按、a
追加;
内存读写
-
StringIO
在内存中读写str
; -
BytestIO
在内存中读写 字节; -
内存写入的内容是否被及时读取、何时会被覆盖,都需要很仔细的查看;
from io import StringIO f = StringIO("Hi! I'm Morton wang.") print("f.getvalue():", f.getvalue()) f.write('hello') f.write(' ') f.write('world!') print("f.getvalue():", f.getvalue()) output————————————————————————— f.getvalue(): Hi! I'm Morton wang. f.getvalue(): hello world!on wang.
from io import BytesIO f = BytesIO() f.write('Python大法好'.encode('utf-8')) print("f.read():", f.read()) print("f.getvalue():", f.getvalue()) # 使用 'Python大法好' 的字节码初始化 f2 = BytesIO(b'Python\xe5\xa4\xa7\xe6\xb3\x95\xe5\xa5\xbd') f2.write('中国'.encode('utf-8')) print("f2.read():", f2.read().decode('utf-8')) print("f2.getvalue():", f2.getvalue().decode('utf-8')) output——————————————————————————— f.read(): b'' f.getvalue(): b'Python\xe5\xa4\xa7\xe6\xb3\x95\xe5\xa5\xbd' f2.read(): 大法好 f2.getvalue(): 中国大法好
操作文件和目录
-
获得系统类型(
nt
表示 Windows)、指定的环境变量;import os print(os.name) print(os.environ.get('CPATH')) output———————————————————————— nt C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.0\include
-
目录部分:路径合并、拆分函数分别使用
os.path.join(path_1, path_2)
os.path.split(path)
,好处就是可以避免不同操作系统的路径不同带来的麻烦,这些函数仅对字符串进行操作,不要求该路径一定存在; -
目录部分:
os.path.isfile(path)
os.path.isdir(path)
分别用来判断该路径是否是文件、目录; -
文件部分:文件重命名、删除文件;
import os # 查看当前目录的绝对路径: absolute_path = os.path.abspath('.') print('absolute_path:\t', absolute_path) # 在某个目录下创建一个新目录,首先把新目录的完整路径表示出来: new_path = os.path.join(absolute_path, 'testdir') print('new_path:\t\t', new_path) # 然后创建一个目录: os.mkdir(new_path) # 删掉一个目录: os.rmdir(new_path) # os.path.split 后一部分是最后级别的目录或者文件名 print(os.path.split('/path/to/file.txt')) print(os.path.split('/path/to/file')) # os.path.splitext 可以获取文件的拓展名 print(os.path.splitext('/path/to/file.txt')) print(os.path.splitext('/path/to/file')) # 文件重命名 os.rename('test.txt', 'test.py') # 文件删除 os.remove('test.py') output———————————————————————— absolute_path: F:\wtlGit\python3_notes new_path: F:\wtlGit\python3_notes\testdir ('/path/to', 'file.txt') ('/path/to', 'file') ('/path/to/file', '.txt') ('/path/to/file', '')
序列化
-
把变量从内存中变成可存储或传输的过程称之为序列化,反过来就是反序列化;
-
序列化为字节码及对应的反序列化:
pickle.dumps(object)
pickle.loads(dumps)
;import pickle student = dict(name='Bob', age=20, score=88) student_dumps = pickle.dumps(student) student_1 = pickle.loads(student_dumps) print("student_dumps:", student_dumps) print("student_1:\t", student_1) output———————————————————— student_dumps: b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x03\x00\x00\x00Bobq\x02X\x03\x00\x00\x00ageq\x03K\x14X\x05\x00\x00\x00scoreq\x04KXu.' student_1: {'name': 'Bob', 'age': 20, 'score': 88}
-
序列化到文件及对应的反序列化:
pickle.dump(object, file)
pickle.load(dump_file)
;import pickle student = dict(name='Bob', age=20, score=88) with open('dump.txt', 'wb') as f: pickle.dump(student, f) with open('dump.txt', 'rb') as f: student_1 = pickle.load(f) print("student:\t", student) print("student_1:\t", student_1) output———————————————————— student: {'name': 'Bob', 'age': 20, 'score': 88} student_1: {'name': 'Bob', 'age': 20, 'score': 88}
-
JSON
是序列化的标准格式,可以在不同的编程语言之间传递对象,并且比XML
更快,而且可以直接在Web
页面中读取,非常方便; -
JSON
标准规定JSON
编码是UTF-8
,表示出来就是一个字符串; -
和
pickle
的使用类似,JSON
也支持序列化到变量和文件,更多的参数使用 在这里import json class Student(object): def __init__(self, name, age, score): self.name = name self.age = age self.score = score def __str__(self): return "name:{} age:{} score:{}".format(self.name, self.age, self.score) def student2dict(std): return { 'name': std.name, 'age': std.age, 'score': std.score } def dict2student(d): return Student(d['name'], d['age'], d['score']) s = Student('Bob', 20, 88) # json 不能直接序列化对象,需要将对象变为 Dict s_json = json.dumps(s, default=student2dict) print(s_json) print(json.dumps(s, default=lambda obj: obj.__dict__)) # 效果同上 print(json.loads(s_json, object_hook=dict2student)) # object2str() output—————————————————————————————————— {"name": "Bob", "age": 20, "score": 88} {"name": "Bob", "age": 20, "score": 88} name:Bob age:20 score:88