数据持久化 - 文件保存本地

斜杠 / 不需要转义,反斜杠 \\ 才需要。

数据持久化

1. 文件操作

计算机的 文件,就是存储在某种 长期储存设备 上的一段 数据

长期存储设备包括:硬盘、U 盘、移动硬盘、光盘…

文本文件和二进制文件

  • 文本文件
    • 可以使用 文本编辑软件 查看
    • 本质上还是二进制文件
    • 例如:python 的源程序
  • 二进制文件
    • 保存的内容 不是给人直接阅读的,而是 提供给其他软件使用的
    • 例如:图片文件、音频文件、视频文件等等
    • 二进制文件不能使用 文本编辑软件 查看

1.1 文件的基本操作

操作文件的函数 / 方法

Python 中要操作文件需要记住 1 个函数和 3 个方法

序号 函数 / 方法名 说明
打开函数 open() 内置方法,打开文件,并且返回文件操作对象
读取方法 .read 将文件内容读取到内存
写入方法 .write 将指定内容写入文件
关闭方法 .close 关闭文件
  • open 函数负责打开文件,并且返回文件对象
  • read/write/close 三个方法都需要通过 文件对象 来调用

1.1.1 读取文件

file = open('filename',mode, encoding, newline)  //newline='\r\n' 可让文件换行写入

函数的第一个参数是要打开的文件名(文件名区分大小写)

  • 如果文件 存在,返回 文件操作对象,以供读写和关闭
  • 如果文件 不存在,会 抛出异常
  • read() 方法可以一次性 读入 并 返回 文件的 所有内容

  • close()方法负责关闭文件

    • 如果 忘记关闭文件,会造成系统资源消耗,而且会影响到后续对文件的访问
  • 注意:read() 方法执行后,会把 文件指针 移动到 文件的末尾

# 1. 打开 - 文件名需要注意大小写
file = open("./data.csv")

# 2. 读取
text = file.read()
print(text)

# 3. 关闭
file.close()

1.1.2 打开文件的方式

  • open 函数 默认 只读方式 打开文件,并且返回文件对象

语法如下:

f = open(" 文件名 ", " 访问方式 ")
访问方式 说明
r 以只读方式打开文件。文件的指针将会放在文件的开头,这是默认模式。如果文件不存在,抛出异常
w 以只写方式打开文件。如果文件存在会被覆盖。如果文件不存在,创建新文件
a 以追加方式打开文件。如果该文件已存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件进行写入
r+ 以读写方式打开文件。文件的指针将会放在文件的开头。如果文件不存在,抛出异常
w+ 以读写方式打开文件。如果文件存在会被覆盖。如果文件不存在,创建新文件
a+ 以读写方式打开文件。如果该文件已存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件进行写入
rb 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。b 是二进制的意思
wb 以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件
ab 以二进制格式打开一个文件用于追加

提示

  • 频繁的移动文件指针,会影响文件的读写效率,开发中更多的时候会以 只读、只写 的方式来操作文件

写入文件示例

# 打开文件
f = open("text.txt", "w")

f.write("hello python!\n")
f.write(" 今天天气真好 ")

# 关闭文件
f.close()

1.1.3 按行读取文件内容

read 方法默认会把文件的 所有内容 一次性读取到内存

如果文件太大,对内存的占用会非常严重

readline 方法

readline 方法可以一次读取一行内容

方法执行后,会把 文件指针 移动到下一行,准备再次读取

—> 读取大文件的正确姿势!

1.1.4 with open

常用三段式的文件操作:open–>read/write–>close。这个我们操作完文件后必须 close,当然我们也可以这样做:

with open('text.txt', 'r', encoding='utf-8') as f:
    for line in f.readlines():
        print(line.strip())           # 打印内容,并把行末尾的 '\n' 删掉

这样就不用调用 close()方法了,可以更为简洁

1.2 目录操作

  • 在 终端 / 文件浏览器、 中可以执行常规的 文件 / 目录 管理操作,例如:

    • 创建、重命名、删除、改变路径、查看目录内容、……
  • Python 中,如果希望通过程序实现上述功能,需要导入 os 模块

1.2.1 系统操作

1.2.2 文件操作

序号 方法名 说明 示例
01 rename 重命名文件 os.rename(源文件名, 目标文件名)
02 remove 删除文件 os.remove(文件名)

1.2.3 目录操作

序号 方法名 说明 示例
01 listdir 目录列表 os.listdir(目录名)
02 mkdir 创建目录 os.mkdir(目录名)
03 rmdir 删除目录 os.rmdir(目录名)
04 chdir 修改工作目录 os.chdir(目标目录)
05 makedirs 生成多层递归目录 os.makedirs(目标目录)
06 path.isdir 判断文件或目录是否存在 os.path.isdir(文件路径)
07 path.exists 判断文件是否存在 os.path.exists(文件路径)
08 path.isfile 判断是否为文件 os.path.isfile(文件路径)
09 path.join 连接目录与文件 os.path.join(path,name)
10 path.getsize 返回文件大小 os.path.getsize(文件路径)
11 path.abspath 返回绝对路径 os.path.abspath(name)
12 path.dirname 返回文件路径 os.path.dirname(name)

提示:文件或者目录操作都支持 相对路径 和 绝对路径

// 判断目录是否存在,存在则删除
import os
file_path='images'
if  os.path.exists(file_path):
    os.rmdir(file_path)

2. excel

openpyxl 是一个 Python 库,用于读取 / 写入 Excel 2010 xlsx / xlsm / xltx / xltm 文件。

它的诞生是因为缺少可从 Python 本地读取 / 写入 Office Open XML 格式的库。

官方文档:https://openpyxl.readthedocs.io/en/stable/usage.html#write-a-workbook

Excel 文件三个对象

workbook: 工作簿,一个 excel 文件包含多个 sheet。
sheet:工作表,一个 workbook 有多个,表名识别,如“sheet1”,“sheet2”等。
cell: 单元格,存储数据对象

1、openpyxl 读写单元格时,单元格的坐标位置起始值是(1,1),即下标最小值为 1,否则报错!

2、openpyxl 支持直接横纵坐标访问,如 A1,B2…

2.1 创建工作簿

只需导入Workbook 对象就可以创建工作簿

from openpyxl import Workbook
# 创建工作簿
wb = Workbook()

如果想写入数据就需要获取一张表

表明创建时会自动命名。它们按顺序编号(Sheet,Sheet1,Sheet2 等)。可以随时通过 Worksheet.title 属性更改此名称:

# 创建一张表
ws = wb.active
ws.title = ' 表 1'

# 创建新表
ws2 = wb.create_sheet(' 表 2')

# 通过表名获取表
ws = wb[' 表 1']

2.2 写入操作

现在我们知道了如何获取工作表,可以开始修改单元格内容了。单元格可以直接作为工作表的键进行访问:

这将使单元格返回 A4,如果尚未存在,则创建一个单元格。可以直接分配值:

# 写入值
ws['A1'] = 42

还有 Worksheet.cell() 方法可以更方便操作。

ws.cell(row=2, column=5).value = 99
ws.cell(row=3, column=5, value=100)

逐行写

# 行内容可以直接被列表覆盖
# ws.append(iterable)
# 添加一行到当前 sheet 的最底部(即逐行追加从第一行开始)
# iterable 必须是 list,tuple,dict,range,generator 类型的。
# 1,如果是 list,将 list 从头到尾顺序添加。
# 2,如果是 dict,按照相应的键添加相应的键值。
ws.append(['This is A1', 'This is B1', 'This is C1'])
ws.append({'A': 'This is A1', 'C': 'This is C1'})
ws.append({1: 'This is A1', 3: 'This is C1'})

同时可以遍历单元格

2.3 案例:

将九九乘法表写入 excel 表

# 写入九九乘法表
ws9 = wb.create_sheet(' 九九乘法表 ')
i = 1
while i < 10:
    j = 1
    while j <= i:
        # print('{} * {} = {}'.format(j, i, j * i), end='\t')
        ws9.cell(row=i, column=j).value = '{} * {} = {}'.format(j, i, j * i)
        j += 1
    i += 1 

2.4 读表操作

# 打开文件:
from openpyxl import load_workbook
wb = load_workbook('sample.xlsx')
# 通过表名获取获取 sheet:
table = wb[' 九九乘法表 ']

# 获取行数和列数:
rows = table.max_row
cols = table.max_column
print(rows, cols)

# 获取单元格值:
# 获取表格内容, 是从第一行第一列是从 1 开始的, 注意不要丢掉 .value
Data = table.cell(row=1, column=1).value
print(Data)

# 获取所有表名
sheet_names = wb.sheetnames
print(sheet_names[0])
ws = wb[(wb.sheetnames[0])]  # index 为 0 为第一张表
# 活动表表名
print(wb.active.title)

逐行读取

# 逐行读 ws9['A1:I9']: 例如('A1:C4')
# 返回一个生成器, 注意取值时要用 value,例如:
for row in table['A1:I9']:
    for cell in row:
        print(cell.value)

显示有多少张表

print(wb.sheetnames)
# 显示表名,表行数,表列数
print(ws9.title)
print(ws9.max_row)
print(ws9.max_column)

保存文件

wb.save("sample1.xlsx")

2.5 操作实例

将猫眼爬虫的数据保存到 Excel 表。

3. json

目的: 将 Python 对象编码为 JSON 字符串,或将 JSON 字符串解码为 Python 对象。

json 模块提供了 API,将内存中的 Python 对象转换为 JSON 序列。JSON 具有以多种语言(尤其是 JavaScript)实现的优点。它在 REST API 中 Web 服务端和客户端之间的通信被广泛应用,同时对于应用程序间通信需求也很有用。

3.1 两个主要方法

3.1.1 json.loads()

作用:把 Json 格式字符串解码转换成 Python 字典对象 。字符串——> 字典 (称之为反序列化)

import json

json_str='{"name": "ACME","shares":"100","price" :"542.23"}'   //json 数据

dict_data=json.loads(json_str)

print(type(dict_data),dict_data)
// 输出结果如下:
<class 'dict'> {'name': 'ACME', 'shares': '100', 'price': '542.23'}

注意:json 中的字符串只能是双引号包围。它也是一种数据格式

注意区分:json.load()用于从 json 文件中读取数据。以下举例说明:

import json
file=open('novel.json',mode='r',encoding='utf-8')
a=json.load(file)   // 注意这里 file 只能有一行才能读取
print(type(a))
// 输出结果如下:
<class 'dict'>

总结,json.loads 读取内存里的数据,json.load 读取文件中的数据。都是把数据反序列化。

3.1.2 json.dumps()

作用:把 Python 字典对象解码转换成 Json 格式字符串。字典——> 字符串 (称之为序列化)

import json

dict_data={'name': 'ACME','shares':100,'price' :542.23}

json_str=json.dumps(dict_data)

print(type(json_str),json_str)
// 输出结果如下:
<class 'str'> {"name": "ACME", "shares": 100, "price": 542.23}

注意区分: json.dump()作用是将 dict 类型的数据转成 str,并写入到 json 文件中,以下举例说明:

import json
dict_data={'name': " 马克 ","shares":100,"price" :542.23}

json.dump(dict_data,open('file.json','w'),ensure_ascii=False)
// 结果:将 dict_data 写入到本地

3.2 保存为 Json

以 json 格式保存文件

import json

data = {
    'name': ' 青灯 ',
    'shares': 100,
    'price': 542.23
}

json_str = json.dumps(data) // 将字典序列化为 json

// 写入 json 数据
with open('data.json', mode='w', encoding='utf-8') as f:
    f.write(json_str)

输出结果如下:

// 本地的 data.json 文件打开如下
{"name": "\u9752\u706f", "shares": 100, "price": 542.23}

解决办法: json_str = json.dumps(data, ensure_ascii=False)

4. CSV 模块简介

csv 文件格式是一种通用的电子表格和数据库导入导出格式。最近我调用 RPC 处理服务器数据时,经常需要将数据做个存档便使用了这一方便的格式。

python 中有一个读写 csv 文件的包,直接 import csv 即可。利用这个 python 包可以很方便对 csv 文件进行操作,一些简单的用法如下。

4.1 写入文件

我们把需要写入的数据放到列表中,写文件时会把列表中的元素写入到 csv 文件中。

import csv

ll = [[1, 2, 3, 4],
      [1, 2, 3, 4],
      [5, 6, 7, 8],
      [5, 6, 7, 8]]

with open('example1.csv', 'w', newline='') as csvfile:
    """
    delimiter: 分割符
    """
    spamwriter = csv.writer(csvfile, delimiter=',')
    for l in ll:
        spamwriter.writerow([1, 2, 3, 4])

可能遇到的问题:直接使用这种写法会导致文件每一行后面会多一个空行。使用 newline='' 解决

使用 open 直接写入

 with open('example2.csv', 'w') as csvfile:
    """
    delimiter: 分割符
    """
    for l in ll:
        csvfile.write(",".join(map(str, l)))
        csvfile.write('\n')

4.2 读取文件

import csv

with open('example.csv', encoding='utf-8') as f:
    csv_reader = csv.reader(f)
    for row in csv_reader:
        print(row)

file:example.csv csv 数据

['1', '2', '3', '4']
['1', '2', '3', '4']
['1', '2', '3', '4']
['1', '2', '3', '4']

默认的情况下, 读和写使用逗号做分隔符(delimiter),当遇到特殊情况是,可以根据需要手动指定字符, 例如:

with open('example.csv', encoding='utf-8') as f:
    reader = csv.reader(f, delimiter=',')
    for row in reader:
        print(row)

上述示例指定冒号作为分隔符

有点需要注意的是,当用 writer 写数据时, None 会被写成空字符串,浮点类型会被调用 repr() 方法转化成字符串。所以非字符串类型的数据会被 str() 成字符串存储。所以当涉及到 unicode 字符串时,可以自己手动编码后存储或者使用 csv 提供的 UnicodeWriter

4.3 写入与读取字典

csv 还提供了一种类似于字典方式的读写,方式如下:

class csv.DictReader(csvfile, fieldnames=None, restkey=None, restval=None, dialect='excel', *args, **kwds)

class csv.DictWriter(csvfile, fieldnames, restval='', extrasaction='raise', dialect='excel', *args, **kwds)

其中 fieldnames 指定字典的 key 值,如果 reader 里没有指定那么默认第一行的元素,在 writer 里一定要指定这个。

# %% 写

import csv

with open('names.csv', 'w') as csvfile:
    fieldnames = ['first_name', 'last_name']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)

    writer.writeheader()
    writer.writerow({'first_name': 'Baked', 'last_name': 'Beans'})
    writer.writerow({'first_name': 'Lovely'})
    writer.writerow({'first_name': 'Wonderful', 'last_name': 'Spam'})
# %% 读
import csv

with open('names.csv', newline='') as csvfile:
    reader = csv.DictReader(csvfile)
    for row in reader:
        print(row['first_name'], row['last_name'])

欢迎各位看官及技术大佬前来交流指导呀,可以邮件至 jqiange@yeah.net