6.1. 文件读写
读写文件是最常见的IO
操作。Python
内置了读写文件的函数,用法和C是兼容的。
读写文件前,我们先必须了解一下,在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘,所以,读写文件就是请求操作系统打开一个文件对象(通常称为文件描述符),然后,通过操作系统提供的接口从这个文件对象中读取数据(读文件),或者把数据写入这个文件对象(写文件)。
- 字符编码
要读取非UTF-8
编码的文本文件,需要给open()
函数传入encoding
参数,例如,读取GBK
编码的文件, 遇到有些编码不规范的文件,你可能会遇到UnicodeDecodeError
,因为在文本文件中可能夹杂了一些非法编码的字符。遇到这种情况,open()
函数还接收一个errors
参数,表示如果遇到编码错误后如何处理。最简单的方式是直接忽略.
1 | '/Users/Administrator/gbk.txt', 'r', encoding='gbk') f = open( |
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()
'hello') f.write(
5
' ') f.write(
1
'world!') f.write(
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
'Hello!\nHi!\nGoodbye!') f = StringIO(
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()
'中文'.encode('utf-8')) f.write(
6
print(f.getvalue())
b'\xe4\xb8\xad\xe6\x96\x87'和
StringIO
类似,可以用一个bytes
初始化BytesIO
,然后,像读文件一样读取。1
2
3
4from io import BytesIO
b'\xe4\xb8\xad\xe6\x96\x87') f = BytesIO(
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 | '{"age": 20, "score": 88, "name": "Bob"}' json_str = |
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 许可协议。转载请注明出处!