拿到数据后,通常需要对数据进行保存、加载等操作
这篇文章将介绍文件、excel、json数据、csv模块的基本操作,容易上手,解决一些简单的数据保存问题
数据持久化
1. 文件操作
计算机的文件,就是存储在某种长期储存设备上的一段数据
长期存储设备包括:硬盘、U 盘、移动硬盘、光盘…
文本文件和二进制文件
- 文本文件
- 可以使用文本编辑软件查看
- 本质上还是二进制文件
- 例如:python 的源程序
- 二进制文件
- 保存的内容不是给人直接阅读的,而是提供给其他软件使用的
- 例如:图片文件、音频文件、视频文件等等
1.1 文件的基本操作
操作文件的函数/方法
在 Python
中要操作文件需要记住 1 个函数和 3 个方法
序号 | 函数/方法 | 说明 |
---|---|---|
01 | open | 打开文件,并且返回文件操作对象 |
02 | read | 将文件内容读取到内存 |
03 | write | 将指定内容写入文件 |
04 | close | 关闭文件 |
open
函数负责打开文件,并且返回文件对象read
/write
/close
三个方法都需要通过 文件对象 来调用
1.1.1 打开文件的方式
open
函数默认以只读方式
打开文件,并且返回文件对象
语法如下:
f = open("文件名", "访问方式")
访问方式 | 说明 |
---|---|
r | 以只读方式打开文件。文件的指针将会放在文件的开头,这是默认模式。如果文件不存在,抛出异常 |
w | 以只写方式打开文件。如果文件存在会被覆盖。如果文件不存在,创建新文件 |
a | 以追加方式打开文件。如果该文件已存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件进行写入 |
r+ | 以读写方式打开文件。文件的指针将会放在文件的开头。如果文件不存在,抛出异常 |
w+ | 以读写方式打开文件。如果文件存在会被覆盖。如果文件不存在,创建新文件 |
a+ | 以读写方式打开文件。如果该文件已存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件进行写入 |
- 频繁的移动文件指针,会影响文件的读写效率,一般用只读、只写的方式操作文件
1.1.2 操作文件
open('hello.txt', 'r')
函数的第一个参数是要打开的文件名(文件名区分大小写)
-
read
方法可以一次性读入并返回文件的所有内容readline
方法可以一次读取一行内容,读完一行后指针指向下一行开头,便于读取大文件readlines
读出文件所有行,返回以每行内容为元素的列表
-
write
方法覆盖写入字符串或字节流writelines
将一个元素为字符串的列表写入文件的首行,自动变成首尾相连的字符串
-
close
方法负责关闭文件如果 忘记关闭文件,会造成系统资源消耗,而且会影响到后续对文件的访问
-
注意:
read
方法执行后,会把 文件指针 移动到 文件的末尾
li = ['hello', 'world', '!', ]
f = open('hello.txt', 'w')
f.writelines(li)
f.close()
f = open('hello.txt', 'r')
s = f.read()
print(s)
f.close()
1.2目录操作
-
在 终端 / 文件浏览器、 中可以执行常规的 文件 / 目录 管理操作,例如:
- 创建、重命名、删除、改变路径、查看目录内容、……
-
在
Python
中,如果希望通过程序实现上述功能,需要导入os
模块
1.2.1 文件操作
序号 | 方法名 | 说明 | 示例 |
---|---|---|---|
01 | rename | 重命名文件 | os.rename(源文件名, 目标文件名) |
02 | remove | 删除文件 | os.remove(文件名) |
1.2.2 目录操作
序号 | 方法名 | 说明 | 示例 |
---|---|---|---|
01 | listdir | 目录列表 | os.listdir(目录名) |
02 | mkdir | 创建目录 | os.mkdir(目录名) |
03 | rmdir | 删除目录 | os.rmdir(目录名) |
04 | getcwd | 获取当前目录 | os.getcwd() |
05 | chdir | 修改工作目录 | os.chdir(目标目录) |
06 | path.isdir | 判断是否是文件 | os.path.isdir(文件路径) |
提示:文件或者目录操作都支持 相对路径 和 绝对路径
值得注意的是,os.mkdir( )只能创建父目录存在的目标目录,而os.makedirs( )可以完全按照路径要求递归创建目录;
os.path.isdir( )用于判断是否有目录存在,而os.path.exists( )判断是否有指定文件存在,关注文件类型
示例:
os.rename('hello.txt', 'helloworld!.txt')
os.remove('helloworld!.txt')
print(os.listdir(r'F:\PycharmProjects\demo316'))#获取指定目录下的所有子目录、文件名
os.mkdir(r'F:\PycharmProjects\666')#在指定路径下创建目录
os.rmdir(r'F:\PycharmProjects\666')
print(os.getcwd())
os.chdir(r'F:\PycharmProjects\666')#将工作目录从当前目录跳转到指定目录
os.path.isdir(r'F:\PycharmProjects\777'):
2. excel
openpyxl是一个Python库,用于读取/写入Excel 2010 xlsx / xlsm / xltx / xltm文件。
它的诞生是因为缺少可从Python本地读取/写入Office Open XML格式的库。
Excel 文件三个对象
workbook: 工作簿,一个excel文件包含多个sheet。
sheet:工作表,一个workbook有多个,表名识别,如“sheet1”,“sheet2”等。
cell: 单元格,存储数据对象
1、openpyxl 读写单元格时,单元格的坐标位置起始值是(1,1),即下标最小值为1,否则报错!
2、openpyxl 支持直接横纵坐标访问,如 A1,B2…
2.1 创建、写入并保存工作簿
只需导入Workbook
对象就可以创建工作簿
表创建时会自动命名,按顺序编号(Sheet,Sheet1,Sheet2等),可以通过Worksheet.title
属性更改此名称。
# -*- coding: utf-8 -*-
from openpyxl import Workbook
# 创建工作簿
wb = Workbook()
# 创建一张表
sheet = wb.active
sheet.title = '表1'
# 创建新表
sheet2 = wb.create_sheet('表2')
在已创建的表中写入内容,通常有三种方式:
# 写入
sheet1['A1'] = 'A1' # 指定表中的位置,实现赋值
sheet1.cell(row=2, column=1, value='A2') # 对单元格进行操作
sheet1.cell(row=3, column=1).value = 'A3' # 同上,写法稍有不同
逐行写:
行内容可以直接被列表覆盖
sheet.append(iterable)
添加一行到当前sheet的最底部(即逐行追加从第一行开始)
iterable必须是list,tuple,dict,range,generator类型的。
1,如果是list,将list从头到尾顺序添加。
2,如果是dict,按照相应的键添加相应的键值。
sheet1.append(['This is A1', 'This is B1', 'This is C1'])
sheet1.append({'A': 'This is A1', 'C': 'This is C1'})
sheet1.append({1: 'This is A1', 3: 'This is C1'})
最后是保存:
# 保存文件 excel 2010
wb.save('demo.xlsx')
2.2 读表操作
from openpyxl import load_workbook
# 加载工作簿
wb = load_workbook('demo.xlsx')
# 通过表明获取指定工作表
table = wb['表2']
# 获取行数和列数
rows = table.max_row
cols = table.max_column
# 循环遍历所有单元格的值
for row in range(rows):
for col in range(cols):
print(table.cell(row=row + 1, column=col + 1).value)
# 获取所有表名
sheet_names = wb.sheetnames
print(sheet_names[0])
ws = wb[(wb.sheetnames[0])] # index为0为第一张表
# 活动表表名
print(wb.active.title)
逐行读取
# 返回一个生成器, 注意取值时要用value,例如:
for row in table['A1:I9']:
for cell in row:
print(cell.value)
3. json
目的: 将 Python 对象编码为 JSON 字符串,并将 JSON 字符串解码为 Python 对象。
json
模块提供了 API,将内存中的 Python 对象转换为 JSON 序列。JSON 具有以多种语言(尤其是 JavaScript)实现的优点。它在 REST API 中 Web 服务端和客户端之间的通信被广泛应用,同时对于应用程序间通信需求也很有用。 下面演示如何将一个Python数据结构转换为JSON:
3.1 编码和解码
Python 的默认原生类型(str
,int
,float
,list
, tuple
,dict
)。
import json
data = {
'name': 'ACME',
'shares': 100,
'price': 542.23
}
json_str = json.dumps(data)
print(json_str)
print(type(json_str))
运行结果:
{"name": "ACME", "shares": 100, "price": 542.23}
<class 'str'>
从无序的字典到有序的字符串,这个过程被称之为序列化。
最终我们将json保存到文件
with open('data.json', mode='w', encoding='utf-8') as f:
f.write(json_str)
如果使用包含中文的json数据,保存到文件中会将中文转为unicode码
data = {
'name': '小明',
}
{"name": "\u5c0f\u660e"}
解决办法: json_str = json.dumps(data, ensure_ascii=False)
3.2 读取数据
将json数据变为字典类型的这个过程被称之为反序列化
with open('data.json', mode='r', encoding='utf-8') as fp:
data = json.load(fp)
print(data)
print(type(data))
print(data['price'])
{'name': 'ACME', 'shares': 100, 'price': 542.23}
<class 'dict'>
542.23
说到这里,可能会有疑问,为什么不直接用str( )将json数据强制变为字符串,再写入文件中保存,因为强制转为字符串后,读取的只能是字符串,用json.dumps( )转为字符串可以理解为给字符串加了一个标记,只有标记存在,才能用json.load( )去读取出字典类型的数据。
3.3 格式化输出
JSON 的结果是更易于阅读的。dumps()
函数接受几个参数以使输出更易读结果。
import json
data = {'a': 'A', 'b': (2, 4), 'c': 3.0}
print('DATA:', repr(data)) # DATA: {'a': 'A', 'b': (2, 4), 'c': 3.0}
unsorted = json.dumps(data)
print('JSON:', json.dumps(data)) # JSON: {"a": "A", "b": [2, 4], "c": 3.0}
编码,然后重新解码可能不会给出完全相同类型的对象。
特别是,元组成为了列表。
JSON跟Python中的字典其实是一样的,事实上JSON的数据类型和Python的数据类型是很容易找到对应关系的,如下面两张表所示。
Python | JSON |
---|---|
dict | object |
list, tuple | array |
str | string |
int, float, int- & float-derived Enums | number |
True / False | true / false |
None | null |
需要注意的是,json除了可以是字典类型,也可以是元素为字典的列表。
4. CSV模块简介
csv文件格式是一种通用的电子表格和数据库导入导出格式。
python中有一个读写csv文件的包,直接import csv
即可。
利用这个python包可以很方便对csv文件进行操作,一些简单的用法如下。
4.1 写入文件
我们把需要写入的数据放到列表中,写文件时会把列表中的元素写入到csv文件中。
import csv
lis = [
[1, 2, 3, 4],
[5, 6, 7, 8],
]
# newline='' 就不会自动换行
with open('demo.csv', mode='w', encoding='utf-8', newline='') as f:
# 实例化一个csv对象 写入数据
csv_writer = csv.writer(f, delimiter='*')
for li in lis:
csv_writer.writerow(li)
delimiter='*'
指定csv格式数据间的分隔符
保存在csv文件下的数据如下所示:
1*2*3*4
5*6*7*8
4.2 读取文件
with open('demo.csv', mode='r', encoding='utf-8') as f:
csv_reader = csv.reader(f)
for row in csv_reader:
print(row)
['1*2*3*4']
['5*6*7*8']
有点需要注意的是,当用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'])