IO编程
由于CPU和内存的速度远远高于外设的速度,所以,在IO编程中,就存在速度严重不匹配的问题。此时有两种策略
- CPU等着, 也就是程序赞同执行后续代码, 等数据写入磁盘后再向下执行, 这种模式称为同步IO
- CPU不等待, 后续代码继续执行, 磁盘慢慢写入, 这种模式称为异步IO
文件读写¶
读写文件前,我们先必须了解一下,在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘,所以,读写文件就是请求操作系统打开一个文件对象(通常称为文件描述符),然后,通过操作系统提供的接口从这个文件对象中读取数据(读文件),或者把数据写入这个文件对象(写文件)
文件对象操作¶
-
基本语法:
open(filename, 'mode') -
完整语法:
open(file, mode='r', buffering=-1, encoding=None, errors=None, neline=None, closefd=True, opener=None) -
参数:
filename–包含了需要访问的文件名称的字符串;mode–打开文件的模式(详解下表);buffering–设置缓冲;encoding–编码方式;errors–报错级别;newline–区分换行符;closefd–传入的file参数类型;opener–设置自定义开启器, 开启器的返回值必须是一个打开的文件描述符
模式 r r+ w w+ a a+ 读 + + + + 写 + + + + + 创建 + + + + 覆盖 + + 指针在开始 + + + + 指针在结尾 + + -
文件对象的方法
方法 参数 描述 f.close() 关闭文件 f.flush() 刷新文件内部缓冲, 直接把内部缓冲区的数据立刻写入文件 f.write() <string> – 写入的文本 将 string写入到文件中, 并返回写入的字符数f.seek() <offset> – 偏移量
<from_what> – 开始的地方(0-开头 1-当前 2-结尾)改变当前文件指针的位置 f.readline() 读取单独的一行 f.read() size– 数据的字节长度读取文件内容 f.readlines() sizesint– 数据的字节长度返回文件中包含的所有行(以列表形式) f.tell() 返回文件指针当前的位置, 从文件开头算起的字节数
注: 使用完一个文件后要记得关闭, 可以使用with语句自动完成这个过程
file-like Object¶
由于Python”鸭子语言”的特性, 使得如果一个对象可以被open()函数返回且有read()方法, 则可以像一个文件一样处理, 这类对象统称为file-like Object; 例如: 内存的字节流, 网络流, 自定义流等等
StringIO就是在内存中创建的file-like Object, 常用作临时缓冲
StringIO 和 BytesIO¶
StringIO¶
StringIO顾名思义就是在内存中读写str; 要把str写入StringIO, 首先需要从io模块导入StringIO类并创建(可以在创建时传入一个str), 之后便可像文件对象一样操作; getvalue()方法用于获取写入后的str
例:
1 | from io import StringIO |
BytesIO¶
如果要操作二进制数据, 就需要使用BytesIO
与StringIO类似, 从io模块中导入BytesIO类, 然后类似可以创建一个对象实现文件对象一般的操作, 只是需要注意的在写入时需要写入二进制数据
操作文件和目录¶
该内容主要使用了 os 模块, 可以作为os模块的详细介绍
环境变量¶
在系统中定义的环境变量, 将保存 os.environ 中(这是一个字典对象), 可以像操作字典一样获取环境变量
操作文件和目录¶
操作文件和目录的函数一部分放在 os 模块中, 一部分放在 os.path 模块中
1 | # 查看当前目录的绝对路径 |
与os.path.join()相同, 在拆分路径时, 不应该直接拆字符串, 而是通过os.path.split()函数拆分(结果为一个list, 第一个为父路径, 第二个为最后一级的文件或目录名); os.path.splitext()可以直接获得文件扩展名(结果为一个列表, 第一个为扩展名之前的字符, 第二个扩展名字符)
1 | # 对文件重命名 |
os模块并未提供复制文件的方法, 原因是复制文件并非由操作系统提供的系统调用, 理论上来说, 通过读写文件并可实现文件的复制 ; 但python提供了sutil模块, 其中有copyfile()函数, 同时在该模块中, 还可以看到许多实用的函数, 可以将其看作os模块的补充
注: 由于对路径操作方法的混乱, 导致之后又加入了pathlib模块来进行路径操作, 同时从对字符串的粗糙操作变成了对Path对象的操作, 保证了程序的健壮性
序列化¶
概念: 变量从内存中变成可存储或传输对象的过程称为序列化; 将变量内容从序列化的对象重新读入到内存的过程称为反序列化
pickle模块序列化¶
Python提供了pickle模块来实现序列化, 参考 pickle模块
pickle.dumps()方法可以将任意对象序列化成一个bytes, 然后就可以把这个bytes写入文件pickle.dump()方法直接将对象序列化后写入一个file-like Object
类似与序列化过程, 反序列化的过程也有两个基本的方法
pickle.loads()方法可以将一个序列化后的对象的bytes反序列化成原对象pickle.load()方法可以将一个file-like Object直接反序列化成原对象
缺点: 用pickle模块序列化的缺点与所有其它编程语言特有的序列化问题一样, 就是它只能用与Python, 且可能不同版本的Python彼此都不兼容, 因此, 只能用pickle保存那些不重要的数据, 不能成功地反序列化也没关系
JSON¶
如果在不同的编程语言之间传递对象, 就必须把对象序列化为标准格式, 如XML, 但更好地方法是序列化为JSON, 因为JSON表示出来就是一个字符串, 可以被所有语言读取, 也可以方便的存储到磁盘或者通过网络传输, 并且JSON比XML更快, 而且可以直接在Web页面中读取
JSON表示的对象就是标准的JavaScript语言的对象,JSON和Python内置的数据类型对应如下:
| JSON类型 | Python类型 |
|---|---|
| {} | dict |
| [] | list |
| “string” | str |
| 1234.56 | int或float |
| true/false | True/False |
| null | None |
Python内置的json模块提供了非常完善的Python对象到JSON格式的转换
与pickle模块相似, json模块也有load(), loads()和dump(), dumps()方法, 含义类似, 只是将序列化后的bytes换为符合JSON格式的字符串
进阶用法¶
Python中的dict对象可以直接序列化为JSON的{}对象, 但如果想将一个class对象序列化为JSON对象, 则还需传入将class对象转换为dict对象的函数的参数[json.dumps(obj, default=函数名); load()/loads()函数相同, 需传入将dict对象转换为class对象的函数]
例:
1 | class Student(object): |
注: 一般对象都有一个特殊的__dict__属性, 用来存储实例变量


