这是机器未来的第26篇文章
原文首发地址:https://blog.csdn.net/RobotFutures/article/details/125647298
模式 | 描述 |
---|---|
t | 文本模式 (默认)。 |
x | 写模式,新建一个文件,如果该文件已存在则会报错。 |
b | 二进制模式。 |
+ | 打开一个文件进行更新(可读可写)。 |
U | 通用换行模式(不推荐)。 |
r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。 |
w | 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。 |
w+ | 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。 |
a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 |
ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
mode的参数组合非常多,那么如何快速理解mode的参数呢?
将其分为2类:读写相关和文本类型相关
以可读方式打开文件。文件的指针会指向文件的开头,这是默认open文件的mode,若文件不存在,则抛出FileNotFoundError异常
以可写的方式打开文件,若文件存在,则清空之前的内容,从头开始写入;如果文件不存在,则创建文件写入。
以追加的方式写入到文件的末尾。如果文件存在,则从文件的末尾继续写入;如果文件不存在,则创建文件写入。
还有一个特殊的模式+,可以追加在r、w、a后面,赋予可读可写功能,但是对于文件是否存在时的处理仍然遵循r、w、b的逻辑
文件一般分为2类:文本文件和二进制文件。
文本文件以字符串模式读写。二进制文件以二进制模式读写。
举个简单的例子,同一个文件用两种不同的模式读写,看下他们的区别。
# 读文件
f = open(file="demo.txt", mode="rt")
print(f.read())
f.close()
机器未来,追逐未来时代的脉搏
# 读文件
f = open(file="demo.txt", mode="rb")
print(f.read())
f.close()
b'\xe6\x9c\xba\xe5\x99\xa8\xe6\x9c\xaa\xe6\x9d\xa5\xef\xbc\x8c\xe8\xbf\xbd\xe9\x80\x90\xe6\x9c\xaa\xe6\x9d\xa5\xe6\x97\xb6\xe4\xbb\xa3\xe7\x9a\x84\xe8\x84\x89\xe6\x90\x8f'
同一个demo.txt文件,使用两种不同的模式读出来的数据展现方式是不一样的:(1)rt模式读出来的是字符串方式展现的;(2)rb模式读出来的是以二进制方式展示的。
以文本模式打开文件,这是默认参数
以二进制模式打开文件,文件中所有的数据,包括字符串结尾的’\0’都被编码为b’\x00’
综合读写相关和文本类型相关,就形成了模式段首的那么多组合模式。
编码的目的是建立语言字符和二进制的映射关系,采用统一的编码规范让信息流通通畅。
常见的编码方式有ASCII编码、GBK编码、UTF-8编码,不同的编码方式对同一个信息的编码方式是不一样的。更多编码可以阅读http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
x = "机器未来,追逐未来时代的脉搏"
# 对文本编码,编码方式为gbk
x2 = x.encode(encoding="gbk")
x2
b'\xbb\xfa\xc6\xf7\xce\xb4\xc0\xb4\xa3\xac\xd7\xb7\xd6\xf0\xce\xb4\xc0\xb4\xca\xb1\xb4\xfa\xb5\xc4\xc2\xf6\xb2\xab'
可以看到使用gbk编码后,每个汉字被编码为2个字节的数据。
# 对编码的文本解码,编码方式为gbk
x3 = x2.decode(encoding="gbk")
# 可以看到还原为原来的信息了
x3
'机器未来,追逐未来时代的脉搏'
使用同样的编码方式解码后,信息被还原。
x4 = x2.decode(encoding="utf-8")
x4
---------------------------------------------------------------------------
UnicodeDecodeError Traceback (most recent call last)
/media/zhoushimin/Work/220_StudyUpUp/新媒体博客同步空间/BaiduSyncdisk/新媒体/Python快速入门系列/python14-file.ipynb Cell 18' in ()
----> 1 x4 = x2.decode(encoding="utf-8")
2 x4
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xbb in position 0: invalid start byte
|
使用不同的编码方式解码,直接报错了。不用的编码方式编码后的数据有信息可以做区分。
# 写文件
f = open(file="demo1.txt", mode="w", encoding="utf-8")
f.write("机器未来,追逐未来时代的脉搏")
f.close()
# 读文件
f = open(file="demo1.txt", mode="r", encoding='utf-8')
print(f.read())
f.close()
机器未来,追逐未来时代的脉搏
注意:编码方式仅在文本模式时有效,否则会报:ValueError: binary mode doesn’t take an encoding argument
# 使用不同的编码方式打开文件会直接报错。
f = open(file="demo1.txt", mode="r", encoding='gbk')
print(f.read())
f.close()
---------------------------------------------------------------------------
UnicodeDecodeError Traceback (most recent call last)
/media/zhoushimin/Work/220_StudyUpUp/新媒体博客同步空间/BaiduSyncdisk/新媒体/Python快速入门系列/python14-file.ipynb Cell 24' in ()
1 # 读文件
2 f = open(file="demo1.txt", mode="r", encoding='gbk')
----> 3 print(f.read())
4 f.close()
UnicodeDecodeError: 'gbk' codec can't decode byte 0xaa in position 8: illegal multibyte sequence
|
在文章的最开始,我们聊到文件的操作流中,最后一个步骤是关闭文件。打开文件会占用内存空间,关闭文件会释放内存空间,如果因为异常抛出导致文件无法关闭,可能会导致内存被耗尽。那么该怎么做好异常处理呢?
可以使用异常处理表达式来处理:
try:
f = open(file="demo1.txt", mode="r", encoding='gbk')
print(f.read())
except Exception as e: # 未知异常的捕获
print(f"发生异常, 异常信息:{e}")
finally:
f.close()
利用finally的特性(无论是否发生异常,最终都会执行)实现不论是否发生异常都会关闭文件。
关闭文件,释放内存除了通过close函数之外,还可以通过with上下文表达式来实现。
with open(file="demo1.txt", mode="r", encoding='gbk') as f:
print(f.read())
在with上下文表达式中,在表达式内的代码块退出时(不论是否抛出异常),都会自动回收内存。
注意:如果需要捕获异常,则建议使用try…finally…表达式,如果想简单优雅可以使用with表达式,但是需要手动识别异常处理,with表达式不会抛出异常
with表达式,是一种常用的文件访问代码样式,使用频次最高。
with open(file="demo1.txt", mode="r", encoding='gbk') as f:
f.read??
Signature: f.read(size=-1, /)
Docstring:
Read at most n characters from stream.
Read from underlying buffer until we have n characters or we hit EOF.
If n is negative or omitted, read until EOF.
Type: builtin_function_or_method
从read函数的描述中可以看到,它有一个参数,可以指定要读取的数据长度,它读到指定长度或到达文件末尾返回。如果指定长度为负数或不填写,则读取整个文件。
# 读多字节编码文字
# demo1.txt的内容为:机器未来,追逐未来时代的脉搏
with open(file="demo1.txt", mode="r", encoding='utf-8') as f:
print(f.read(size=2))
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/media/zhoushimin/Work/220_StudyUpUp/新媒体博客同步空间/BaiduSyncdisk/新媒体/Python快速入门系列/python14-file.ipynb Cell 28' in ()
1 # 读多字节编码文字
2 # demo1.txt的内容为:机器未来,追逐未来时代的脉搏
3 with open(file="demo1.txt", mode="r", encoding='utf-8') as f:
----> 4 print(f.read(size=2))
TypeError: read() takes no keyword arguments
|
# 读单字节编码文字
# demo2.txt的内容为1234abcd
with open(file="demo2.txt", mode="r", encoding='utf-8') as f:
print(f.read(2))
12
上面2个例子分别展现了读取多字节编码和单字节编码,可以发现个有趣的现象,汉字文件,读取文件为2,我的理解是读取2个字节数据,但是显然不是,它读取了2个汉字出来了,这是为什么呢,它的单位是什么?以文字占用的字节数为单位吗?做一下测试验证一下!
# demo3.txt的文件内容为:机器未来1234455,汉字和数字混排
with open(file="demo3.txt", mode="r", encoding='utf-8') as f:
print(f.read(6))
机器未来12
文件中既有汉字,也有数字,读取长度为6,读取了4个汉字,2个数字,可以说明,在rt模式下读取文件,读取的长度是以文字的个数为单位的,一个汉字占2个字节,那么实际读取长度为2,那么如何按照字节来读取数据呢?测试一下二进制模式读取!
with open(file="demo3.txt", mode="rb") as f:
print(f.read(6))
b'\xe6\x9c\xba\xe5\x99\xa8'
可以看到使用rb二进制模式读取时,读取的长度就是6,与读取长度一致。读出来的数据对应【机器未】。
总结一下:以r模式读取数据时,是以文字(character)的个数为单位的,如果是汉字,那么实际读取2字节,如果是英文字母,那么实际读取1字节;以rb模式读取数据时,指定的长度是多长,读取的数据长度就是多长
一次读取一行数据,并且保留原文本行末换行符
with open(file="demo1.txt", mode="r", encoding='gbk') as f:
f.readline??
Signature: f.readline(size=-1, /)
Docstring:
Read until newline or EOF.
Returns an empty string if EOF is hit immediately.
Type: builtin_function_or_method
可以看到readline也是支持参数的,默认值为-1,表示读到换行符或文件末尾返回,如果执行大于0的值,则读取对应个数的文字(character)。
注意:不能使用关键字参数的方式传参,只能使用位置参数的方式传参,因为参数末尾为斜杠,禁止关键字传参,更多函数参数相关请参考博文之前的博文:【【Python零基础入门笔记 | 09】高级程序员绝世心法——模块化之函数封装
】
# 按照文字长度读取
with open(file="demo1.txt", mode="r", encoding='utf-8') as f:
print(f.readline(4))
机器未来
# 不传参,读整行
# demo1.txt的内容为
# 机器未来,追逐未来时代的脉搏1
# 机器未来,追逐未来时代的脉搏2
# 机器未来,追逐未来时代的脉搏3
# 机器未来,追逐未来时代的脉搏4
with open(file="demo.txt", mode="r", encoding='utf-8') as f:
print(f.readline())
机器未来,追逐未来时代的脉搏1
可以看到readline读取了一行数据。
readlines读取文件所有行并返回列表,列表中的每一个元素就是文件中的每一行数据,每行都会保留末尾的换行符
# 不传参,读整行
# demo1.txt的内容为
# 机器未来,追逐未来时代的脉搏1
# 机器未来,追逐未来时代的脉搏2
# 机器未来,追逐未来时代的脉搏3
# 机器未来,追逐未来时代的脉搏4
with open(file="demo.txt", mode="r", encoding='utf-8') as f:
f.readlines??
Signature: f.readlines(hint=-1, /)
Docstring:
Return a list of lines from the stream.
hint can be specified to control the number of lines read: no more
lines will be read if the total size (in bytes/characters) of all
lines so far exceeds hint.
Type: builtin_function_or_method
readlines也有一个位置参数hint,默认值为-1,表示读取所有行,也可以指定读取hint行,一般我们使用默认参数即可。
# 不传参,读整行
# demo1.txt的内容为
# 机器未来,追逐未来时代的脉搏1
# 机器未来,追逐未来时代的脉搏2
# 机器未来,追逐未来时代的脉搏3
# 机器未来,追逐未来时代的脉搏4
with open(file="demo.txt", mode="r", encoding='utf-8') as f:
print(f.readlines())
['机器未来,追逐未来时代的脉搏1\n', '机器未来,追逐未来时代的脉搏2\n', '机器未来,追逐未来时代的脉搏3\n', '机器未来,追逐未来时代的脉搏4']
向文件中写入数据
with open(file="demo1.txt", mode="w", encoding='utf-8') as f:
f.write??
Signature: f.write(text, /)
Docstring:
Write string to stream.
Returns the number of characters written (which is always equal to
the length of the string).
Type: builtin_function_or_method
从write函数的描述中可以看到,其有一个位置参数text,看示例:
# 写入文本数据
with open(file="demo4.txt", mode="w", encoding='utf-8') as f:
f.write("机器未来")
with open(file="demo4.txt", mode="r", encoding='utf-8') as f:
print(f.readline())
机器未来
# 写入二进制数据
with open(file="demo5.txt", mode="wb") as f:
f.write(b"\x12\x12\x12\x12\x12\x00\x12\x12")
with open(file="demo5.txt", mode="rb") as f:
print(f.readline())
b'\x12\x12\x12\x12\x12\x00\x12\x12'
写入多行数据,没有writeline函数。以列表的形式写入到文件,每个元素为一行数据。需要注意的事:如果需要换行,换行符需要手动添加。
# 写入文本数据
with open(file="demo5.txt", mode="w", encoding='utf-8') as f:
f.writelines?
Signature: f.writelines(lines, /)
Docstring:
Write a list of lines to stream.
Line separators are not added, so it is usual for each of the
lines provided to have a line separator at the end.
Type: builtin_function_or_method
# 写入文本数据
with open(file="demo5.txt", mode="w", encoding='utf-8') as f:
f.writelines(['机器未来,追逐未来时代的脉搏1\n', '机器未来,追逐未来时代的脉搏2\n', '机器未来,追逐未来时代的脉搏3\n', '机器未来,追逐未来时代的脉搏4'])
with open(file="demo.txt", mode="r", encoding='utf-8') as f:
print(f.readlines())
['机器未来,追逐未来时代的脉搏1\n', '机器未来,追逐未来时代的脉搏2\n', '机器未来,追逐未来时代的脉搏3\n', '机器未来,追逐未来时代的脉搏4']
最常用不过是joblib和pickle了。
文件以什么结构写入,就以什么结构读出。
看下面这个例子,数据结构为字典,写入时直接以字典结构写入,取出时仍然是原来的结构
import pickle
data = {"a":2, "b":3, "c":4}
# 写入
file = open("data.pkl", "wb")
pickle.dump(data, file)
file.close()
# 读取
file2 = open("data.pkl", "rb")
data2 = pickle.load(file2)
print(data2)
file2.close()
可以看到例子的使用和普通文件的接口操作大同小异,都是打开文件->读写文件->关闭文件。
joblib更加简洁,仅需要dump和load接口即可。
from __future__ import print_function
from sklearn import svm
from sklearn import datasets
from sklearn.externals import joblib
clf = svm.SVC()
iris = datasets.load_iris()
X, y = iris.data, iris.target
print(X)
print(y)
clf.fit(X, y)
# Save
joblib.dump(clf, 'save/clf.pkl')
# restore
clf3 = joblib.load('save/clf.pkl')
print(clf3.predict(X[0:1]))
以上就是数据持久化文件相关的学习总结了,下一节讲讲常用的库。
《Python零基础快速入门系列》快速导航:
写在末尾:
- 博客简介:专注AIoT领域,追逐未来时代的脉搏,记录路途中的技术成长!
- 专栏简介:本专栏的核心就是:快!快!快!2周快速拿下Python,具备项目开发能力,为机器学习和深度学习做准备。
- 面向人群:零基础编程爱好者
- 专栏计划:接下来会逐步发布跨入人工智能的系列博文,敬请期待
- Python零基础快速入门系列
- 快速入门Python数据科学系列
- 人工智能开发环境搭建系列
- 机器学习系列
- 物体检测快速入门系列
- 自动驾驶物体检测系列
- …