6.1. 文件读写
读写文件是最常见的IO操作。Python内置了读写文件的函数,用法和C是兼容的。
读写文件前,我们先必须了解一下,在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘,所以,读写文件就是请求操作系统打开一个文件对象(通常称为文件描述符),然后,通过操作系统提供的接口从这个文件对象中读取数据(读文件),或者把数据写入这个文件对象(写文件)。
- 字符编码
 
要读取非UTF-8编码的文本文件,需要给open()函数传入encoding参数,例如,读取GBK编码的文件, 遇到有些编码不规范的文件,你可能会遇到UnicodeDecodeError,因为在文本文件中可能夹杂了一些非法编码的字符。遇到这种情况,open()函数还接收一个errors参数,表示如果遇到编码错误后如何处理。最简单的方式是直接忽略.
1  | f = open('/Users/Administrator/gbk.txt', 'r', encoding='gbk')  | 
6.2. StringIO和BytesIO
很多时候,数据读写不一定是文件,也可以在内存中读写。
StringIO:在内存中读写str要把
str写入StringIO,我们需要先创建一个StringIO,然后,像文件一样写入即可:1
2
3
4
5
6
7
8
9
10
11from io import StringIO
f = StringIO()
f.write('hello')
5
f.write(' ')
1
f.write('world!')
6
# `getvalue()`方法用于获取写入后的`str`
print(f.getvalue())
hello world!要读取
StringIO,可以用一个str初始化StringIO,然后像文件一样读取1
2
3
4
5
6
7
8
9
10
11from io import StringIO
f = StringIO('Hello!\nHi!\nGoodbye!')
while True:
s = f.readline()
if s == '':
break
print(s.strip())
...
Hello!
Hi!
Goodbye!
BytesIO:StringIO操作的只能是str,如果要操作二进制数据,就需要使用BytesIO。BytesIO实现了在内存中读写bytes,我们创建一个BytesIO,然后写入一些bytes。请注意,写入的不是str,而是经过UTF-8编码的bytes。1
2
3
4
5
6from io import BytesIO
f = BytesIO()
f.write('中文'.encode('utf-8'))
6
print(f.getvalue())
b'\xe4\xb8\xad\xe6\x96\x87'和
StringIO类似,可以用一个bytes初始化BytesIO,然后,像读文件一样读取。1
2
3
4from io import BytesIO
f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')
f.read()
b'\xe4\xb8\xad\xe6\x96\x87'
6.3. bytes函数的使用
bytes函数返回一个新的bytes对象,该对象是一个0<=x<=256区间的整数不可变序列,它是bytearray的不可变版本。
bytes([source[, encoding[, errors]]]):返回一个新的bytes对象- 如果
source为整数,则返回一个长度为source的初始化数组 - 如果
source为字符串,则按照指定的encoding将字符串转化为字节序列 - 如果
source为可迭代类型,则元素必须[0, 255]中的整数 - 如果
source为与buffer接口一致的对象,则此对象也可以被用于初始化bytearray - 如果没有输入任何参数,默认就是初始化数组为0个元素
 
- 如果
 
1  | a = bytes([1, 2, 3, 4])  | 
6.4. 序列化
一般数据持久化存储采用三种方式:普通文件、数据库、序列化
pickle:pickle.dump(obj, fp)将对象存储到文件,pickle.load(fp)将文件转化为对象1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18import pickle
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
# 存储:对象=>文件
xiaoming = Person('xiaoming', 18)
fp = open('text.txt', 'wb')
pickle.dump(xiaoming, fp)
print('对象数据存储完毕!')
fp.close()
# 读取:文件=>对象
fp = open('text.txt', 'rb')
xiaoming = pickle.load(fp)
print(xiaoming.name, xiaoming.age)
fp.close()json:如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。
| JSON类型 | Python类型 | 
|---|---|
| {} | dict | 
| [] | list | 
| string | str | 
| 1234.56 | int或float | 
| true/false | True/False | 
| null | None | 
Python内置的json模块提供了非常完善的Python对象到JSON格式的转换。我们先看看如何把Python对象变成一个JSON.dumps()方法返回一个str,内容就是标准的JSON。类似的,dump()方法可以直接把JSON写入一个file-like Object。
1  | import json  | 
要把JSON反序列化为Python对象,用loads()或者对应的load()方法,前者把JSON的字符串反序列化,后者从file-like Object中读取字符串并反序列化。由于JSON标准规定JSON编码是UTF-8,所以我们总是能正确地在Python的str与JSON的字符串之间转换。
1  | json_str = '{"age": 20, "score": 88, "name": "Bob"}'  | 
Python的dict对象可以直接序列化为JSON的{},不过,很多时候,我们更喜欢用class表示对象,比如定义Student类,然后序列化:
1  | import json  | 
同样的道理,如果我们要把JSON反序列化为一个Student对象实例,loads()方法首先转换出一个dict对象,然后,我们传入的object_hook函数负责把dict转换为Student实例:
1  | def dict_to_student(d):  | 
- 本文作者: Lajos
 - 本文链接: https://www.lajos.top/2020/05/03/No-6-Python语言基础-IO编程/
 - 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!
 
		