纸上得来终觉浅,绝知此事要躬行。
1. 文件打开
日常我们使用中,涉及最多就应该是对文件的处理了,其中文件的读取模式主要涉及到
open
函数,而该函数的参数又比较多,所以理解该函数才是文件处理的核心要点。
- open:核心函数
open(file, mode='r',
buffering=-1, encoding=None, errors=None,
newline=None, closefd=True, opener=None)
# 使用open函数打开文件
try:
f = open('note.txt', 'r')
print(f.read())
finally:
f.close()
# 使用with文件上下文管理器
with open('note.txt', 'r') as f:
print(f.read())
- (1)mode:指定文件的读取模式
Character | Meaning | Description |
---|---|---|
r |
open for reading (default) | 只读模式(默认) |
w |
open for writing, truncating the file first | 只写模式 |
x |
create a new file and open it for writing | 创建新文件并打开写模式 |
a |
open for writing, appending to the end of the file if it exists | 追加模式 |
b |
binary mode | 二进制模式 |
t |
text mode (default) | 文本模式(默认) |
+ |
open a disk file for updating (reading and writing) | 读写模式 |
U |
| r r+ w w+ a a+ x x+
---------------------|----------------------------------
allow read | ✓ ✓ ✓ ✓ ✓
allow write | ✓ ✓ ✓ ✓ ✓ ✓ ✓
create new file | ✓ ✓ ✓ ✓ ✓ ✓
open existing file | ✓ ✓ ✓ ✓ ✓ ✓
erase file contents | ✓ ✓
allow seek | ✓ ✓ ✓ ✓ ✓
position at start | ✓ ✓ ✓ ✓ ✓ ✓
position at end | ✓ ✓
In [1]: f = open('update_chis.sh', 'r')
In [2]: f
Out[2]: <_io.TextIOWrapper name='update_chis.sh' mode='r' encoding='UTF-8'>
- (2)buffering:设置缓存大小
- 文本模式下,不设置此参数,遇到换行刷新
buffer
- 二进制模式下,不设置此参数,根据操作系统自动判断
buffer
大小 - 二进制模式下,设置此参数为
0
,关闭buffer
- 文本模式下,不设置此参数,遇到换行刷新
In [4]: f = open('update_chis.sh', buffering=1024)
- (3)encoding:指定编码格式
encoding
参数只在文本模式下生效
In [7]: f = open('update_chis.sh', encoding='utf-8')
- (4)errors:指定无法解码时的处理模式
errors
只在文本模式下生效- 参数
strict
表示严格模式,无法解码抛出异常 - 参数
ignore
表示忽略模式,无法解码直接pass
In [20]: with open('xxx.txt', errors='ignore') as f:
...: pass
...:
- (5)newline:指定换行符
newline
所指定换行符None
、''
、\n
、\r
、\r\n
In [21]: !echo "a.\nb.\nc." > note.txt
In [23]: cat note.txt
a.
b.
c.
In [24]: f = open('note.txt', newline='\n')
In [25]: f.readlines()
Out[25]: ['a.\n', 'b.\n', 'c.\n']
In [26]: f.close()
2. 文件对象
我们这里介绍一下,常用的文件操作函数。
- close 函数
- 关闭文件对象,并清空缓冲区
closed
属性用来判断文件是否已经关闭- 在编程中最好使用
with open
方法,会自动关闭文件
In [27]: f = open('note.txt', node='rt')
In [28]: f.close()
- fileno 函数
- 返回一个文件描述符
name
属性用来获取文件名称
In [29]: f = open('note.txt', mode='rt')
In [30]: f.fileno
Out[30]: <function TextIOWrapper.fileno>
In [31]: f.fileno()
Out[31]: 11
In [33]: f.name
Out[33]: 'note.txt'
- flush 函数
- 强制刷新缓冲区
- 将写入在缓冲区的内容,直接写入文件
In [45]: f = open('note.txt', mode='w')
In [47]: f.write('abc')
Out[47]: 3
In [48]: !cat note.txt
In [49]: f.flush()
In [50]: !cat note.txt
abc
In [51]: f.close()
- read 函数
- 读取时包括换行符
- 读取文件,指定长度,表示可以指定读取字节(二进制)或者字符(文本模式)
- 读取文件,不指定长度,表示读取到文件末尾,参数
-1
同理
In [51]: !echo "a.\nb.\nc." > note.txt
In [52]: f = open('note.txt', 'r+')
In [53]: f.read(2)
Out[53]: 'a.'
In [54]: f.read(2)
Out[54]: '\nb'
In [55]: f.close()
- readline 函数
readline
函数经常和strip
函数一起使用,用于除去行尾换行符readlines
函数一次读入所有行,将结果保存到一个列表中,包含换行符- 当读到文件末尾时,
read
和readline
返回空string
/空bytes
,而readlines
返回空的list
列表
In [56]: f = open('note.txt', 'r+')
In [57]: f.readline()
Out[57]: 'a.\n'
In [58]: f.readline()
Out[58]: 'b.\n'
In [59]: f.close()
In [60]: f = open('note.txt', 'r+')
In [61]: f.readlines()
Out[61]: ['a.\n', 'b.\n', 'c.\n']
In [62]: f.close()
- seek 函数
- 移动文件指针
seek
函数中,参数whence
表示从哪里开始移动- 当文本模式打开时,
whence
只能是0
- 当二进制模式打开时,
whence
都可用
whence | Description |
---|---|
0 |
从起始位置开始移动,offset 偏移量应为零或者整数 |
1 |
从当前位置开始移动,offset 偏移量可能为负数 |
2 |
从末尾位置开始移动,offset 偏移量通常为负数 |
In [63]: f = open('note.txt', 'r+')
In [64]: f.readline()
Out[64]: 'a.\n'
In [65]: f.seek(0)
Out[65]: 0
In [66]: f.readline()
Out[66]: 'a.\n'
In [67]: f.tell()
Out[67]: 3
In [68]: f.seekable()
Out[68]: True
In [70]: f.closed
Out[70]: False
In [72]: f.close()
- write 函数
- 写操作时,换行符始终需要显示传入
- 每次以单行的方式写文件,多行的话需要添加换行符
\n
writelines
函数用于写入字符串,和write
函数类似(字符串也是可迭代对象)writelines
函数用于写入一个可迭代对象,循环遍历写入,不会在每个元素之后自动添加换行符,需要手动添加\n
符号
In [73]: f = open('note.txt', 'a+')
In [74]: f.writable()
Out[74]: True
In [75]: f.write('d\n')
Out[75]: 2
In [76]: f.writelines(['e', 'f'])
In [77]: f.flush()
In [78]: !cat note.txt
a.
b.
c.
d
ef
In [79]: f.close()
3. 序列化和反序列化
在分布式系统中,很多数据都是需要传输的,所以就需要将数据转换成可传输的二进制流。传输到对应机器上之后,又需要把该二进制流转成对应数据,这就是序列化和反序列化。
pickle
- 适用范围
- 这是
Python
自带的序列化和反序列化工具
- 这是
- 参数说明
object
: 要持久化保存的对象,即用于传输的数据。file
: 一个拥有write()
方法的对象,并且这个write()
方法能接收一个字符串作为参数。这个对象可以是一个以写模式打开的文件对象或者一个StringIO
对象,或者其他自定义的满足条件的对象。protoco
: 这是一个可选的参数,默认为0
。如果设置为1
或True
,则以高压缩的二进制格式保存持久化后的对象,否则以ASCII
格式保存。
# 官方文档
Functions:
dump(object, file[, protocol])
dumps(object[, protocol]) -> string
load(file) -> object
loads(string) -> object
- 示例说明
In [80]: import pickle
In [81]: dct = { 'a': 1, 'b': 2, 'c':3 }
In [82]: pickle_date = pickle.dumps(dct)
In [83]: pickle_date
Out[83]: b'\x80\x03}q\x00(X\x01\x00\x00\x00aq\x01K\x01X\x01\x00\x00\x00bq\x02K\x02X\x01\x00\x00\x00cq\x03K\x03u.'
In [85]: with open('data.pickle', 'wb') as f:
...: f.write(pickle_date)
...:
In [87]: with open('data.pickle', 'rb') as f:
...: print(pickle.loads(f.read()))
...:
{'a': 1, 'b': 2, 'c': 3}
json
- 适用范围
pickle
和json
的转换协议不同,所以看到的结果也不一样- 通常会优先使用
json
格式,因为其跨平台的特性,用起来很方便
In [89]: import json
In [90]: dct = { 'a': 1, 'b': 2, 'c':3 }
In [91]: json_data = json.dumps(dct)
In [92]: json_data
Out[92]: '{"a": 1, "b": 2, "c": 3}'
In [93]: with open('json_date', 'w') as f:
...: f.write(json_data)
...:
In [94]: with open('json_data') as f:
...: data = json.loads(f.read())
...: print(data)
...:
- 示例说明
Encoding basic Python object hierarchies::
>>> import json
>>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
'["foo", {"bar": ["baz", null, 1.0, 2]}]'
>>> print(json.dumps("\"foo\bar"))
"\"foo\bar"
>>> print(json.dumps('\u1234'))
"\u1234"
>>> print(json.dumps('\\'))
"\\"
>>> print(json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True))
{"a": 0, "b": 0, "c": 0}
>>> from io import StringIO
>>> io = StringIO()
>>> json.dump(['streaming API'], io)
>>> io.getvalue()
'["streaming API"]'
Compact encoding::
>>> import json
>>> from collections import OrderedDict
>>> mydict = OrderedDict([('4', 5), ('6', 7)])
>>> json.dumps([1,2,3,mydict], separators=(',', ':'))
'[1,2,3,{"4":5,"6":7}]'
Pretty printing::
>>> import json
>>> print(json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=4))
{
"4": 5,
"6": 7
}
Decoding JSON::
>>> import json
>>> obj = ['foo', {'bar': ['baz', None, 1.0, 2]}]
>>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]') == obj
True
>>> json.loads('"\\"foo\\bar"') == '"foo\x08ar'
True
>>> from io import StringIO
>>> io = StringIO('["streaming API"]')
>>> json.load(io)[0] == 'streaming API'
True
Specializing JSON object decoding::
>>> import json
>>> def as_complex(dct):
... if '__complex__' in dct:
... return complex(dct['real'], dct['imag'])
... return dct
...
>>> json.loads('{"__complex__": true, "real": 1, "imag": 2}',
... object_hook=as_complex)
(1+2j)
>>> from decimal import Decimal
>>> json.loads('1.1', parse_float=Decimal) == Decimal('1.1')
True
Specializing JSON object encoding::
>>> import json
>>> def encode_complex(obj):
... if isinstance(obj, complex):
... return [obj.real, obj.imag]
... raise TypeError(repr(obj) + " is not JSON serializable")
...
>>> json.dumps(2 + 1j, default=encode_complex)
'[2.0, 1.0]'
>>> json.JSONEncoder(default=encode_complex).encode(2 + 1j)
'[2.0, 1.0]'
>>> ''.join(json.JSONEncoder(default=encode_complex).iterencode(2 + 1j))
'[2.0, 1.0]'
Using json.tool from the shell to validate and pretty-print::
$ echo '{"json":"obj"}' | python -m json.tool
{
"json": "obj"
}
$ echo '{ 1.2:3.4}' | python -m json.tool
Expecting property name enclosed in double quotes: line 1 column 3 (char 2)