【Python零基础入门笔记 | 14】深度学习如何保存训练好的模型,请看数据持久化之文件操作(2)

这是机器未来的第26篇文章

原文首发地址:https://blog.csdn.net/RobotFutures/article/details/125647298

3. open函数详解

3.2 mode参数

模式 描述
t 文本模式 (默认)。
x 写模式,新建一个文件,如果该文件已存在则会报错。
b 二进制模式。
+ 打开一个文件进行更新(可读可写)。
U 通用换行模式(不推荐)。
r 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
rb 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。
r+ 打开一个文件用于读写。文件指针将会放在文件的开头。
rb+ 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。
w 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
w+ 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb+ 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
a 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
ab 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
a+ 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
ab+ 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。

mode的参数组合非常多,那么如何快速理解mode的参数呢?

将其分为2类:读写相关和文本类型相关

3.2.1 读写相关

  • 读r

以可读方式打开文件。文件的指针会指向文件的开头,这是默认open文件的mode,若文件不存在,则抛出FileNotFoundError异常

  • 写w

以可写的方式打开文件,若文件存在,则清空之前的内容,从头开始写入;如果文件不存在,则创建文件写入。

  • 追加a

以追加的方式写入到文件的末尾。如果文件存在,则从文件的末尾继续写入;如果文件不存在,则创建文件写入。

  • 可读可写+

还有一个特殊的模式+,可以追加在r、w、a后面,赋予可读可写功能,但是对于文件是否存在时的处理仍然遵循r、w、b的逻辑

3.2.2 文本类型相关

文件一般分为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模式读出来的是以二进制方式展示的。

  • 文本t

以文本模式打开文件,这是默认参数

  • 二进制b

以二进制模式打开文件,文件中所有的数据,包括字符串结尾的’\0’都被编码为b’\x00’

综合读写相关和文本类型相关,就形成了模式段首的那么多组合模式。

3.3 编码方式encoding

编码的目的是建立语言字符和二进制的映射关系,采用统一的编码规范让信息流通通畅。

常见的编码方式有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

3.4 close关闭文件

在文章的最开始,我们聊到文件的操作流中,最后一个步骤是关闭文件。打开文件会占用内存空间,关闭文件会释放内存空间,如果因为异常抛出导致文件无法关闭,可能会导致内存被耗尽。那么该怎么做好异常处理呢?

可以使用异常处理表达式来处理:

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表达式,是一种常用的文件访问代码样式,使用频次最高。

4. 读数据相关函数

4.1 read

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模式读取数据时,指定的长度是多长,读取的数据长度就是多长

4.2 readline

一次读取一行数据,并且保留原文本行末换行符

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读取了一行数据。

4.3 readlines

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']

5. write写相关函数

5.1 write

向文件中写入数据

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'

5.3 writelines

写入多行数据,没有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']

6. 扩展:人工智能用来保存数据最常用的文件接口有哪些?

最常用不过是joblib和pickle了。

6.1 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()

可以看到例子的使用和普通文件的接口操作大同小异,都是打开文件->读写文件->关闭文件。

6.2 joblib

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零基础快速入门系列》快速导航:

  • 【Python零基础入门笔记 | 01】 人工智能序章:开发环境搭建Anaconda+VsCode+JupyterNotebook(零基础启动)
  • 【Python零基础入门笔记 | 02】一文快速掌握Python基础语法
  • 【Python零基础入门笔记 | 03】AI数据容器底层核心之Python列表
  • 【Python零基础入门笔记 | 04】为什么内存中最多只有一个“Love“?一文读懂Python内存存储机制
  • 【Python零基础入门笔记 | 05】Python只读数据容器:列表List的兄弟,元组tuple
  • 【Python零基础入门笔记 | 06】字符串、列表、元组原来是一伙的?快看序列Sequence
  • 【Python零基础入门笔记 | 07】成双成对之Python数据容器字典
  • 【Python零基础入门笔记 | 08】无序、不重复、元素只读,Python数据容器之集合
  • 【Python零基础入门笔记 | 09】高级程序员绝世心法——模块化之函数封装
  • 【Python零基础入门笔记 | 10】类的设计哲学:自然法则的具现
  • 【Python零基础入门笔记 | 11】函数、类、模块和包如何构建四级模块化体系
  • 【Python零基础入门笔记 | 12】程序员为什么自嘲面向Bug编程?
  • 【Python零基础入门笔记 | 13】面对海量数据,如何优雅地加载数据?请看迭代器与生成器

写在末尾:

  • 博客简介:专注AIoT领域,追逐未来时代的脉搏,记录路途中的技术成长!
  • 专栏简介:本专栏的核心就是:快!快!快!2周快速拿下Python,具备项目开发能力,为机器学习和深度学习做准备。
  • 面向人群:零基础编程爱好者
  • 专栏计划:接下来会逐步发布跨入人工智能的系列博文,敬请期待
    • Python零基础快速入门系列
    • 快速入门Python数据科学系列
    • 人工智能开发环境搭建系列
    • 机器学习系列
    • 物体检测快速入门系列
    • 自动驾驶物体检测系列

你可能感兴趣的:(Python零基础快速入门系列,python,开发语言,python学习笔记,Python基础)