本系列是学习 廖雪峰 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