文件
数据持久化的一种方式
Python程序运行时写在各种属性,变量,容器中的数据都保存在内存中,内存是 易失存储器
当程序运行结束或内存空间被释放,这些数据也就不复存在了
文件是将数据保存在硬盘等 非易失存储器
上,以达到数据持久化保存的目的
文件路径
绝对路径: 基于盘符或根目录来查找的路径
# Windows
path = 'C:\Programe Files\PyCharm\PyCharm.exe'
# Linux
path = '/root/project/abc.py'
相对路径: 基于当前文件来查找的路径
# Windows
path = '../a/b/c.txt' # ../ 返回上一级目录
# Linux
path = '..\a\b\c.py'
文件读写
open(file,mode)
:打开文件并返回一个流(建立一条通道)
file
:要打开的文件
mode
:指定是输入流还是输出流(通道是单向的)
r
:为读而打开的流(默认)w
:为写而打开的流(截断文件再写入,可以理解为清空重写)x
:创建新文件并且打开写入流a
:打开写入流,在文件末尾追加内容b
:二进制,需要与r
w
x
a
匹配使用t
:文本模式(默认缺省的)+
:同时操作读写流
读取文件的操作 (如果出现乱码需要注意编码规则encoding)
# 访问文件并得到流对象
rstream = open('a.txt','r') # 以读取的方式打开a.txt
# 通过流对象进行读取操作
line = rstream.readline() # 读取a.txt中的一行并返回一个字符串
lines = rstream.readlines() # 读取a.txt中所有内容并返回一个列表
all = rstream.read() # 读取a.txt中所有内容并返回一个字符串
# 释放流对象资源
rstream.close() # 关闭连接
# 访问文件并得到流对象,调用结束后会自动释放资源
with open(r'路径\a.txt','r') as rstream:
all = rstream.read()
print(all)
写文件的操作 (若无目标文件,则自动创建)
aim = ['123\n','4586\n','57468\n']
with open(r'路径\a.txt','a') as wstream: # 以追加写入方式打开a.txt
wstream.write('write-write-write\n') # 写入一行内容
wstream.writeline(aim) # 传入列表,写入多行内容(没有换行效果,要自己加)
文件复制
先读后写即可实现复制
# 读源文件 图片文件要用二进制读写
with open(r'路径\a.png','rb') as rstream:
content = rstream.read()
# 写目标文件
with open(r'路径\b.png','wb') as wstream:
wstream.write(content)
CSV
CSV,逗号分隔值文件。可以由数据库系统导出并用电子表格软件加载
文件读写
读写列表:
import csv
listx = ['a','v','b','e','x'] # 要写入的列表
file_path = r'a.csv'
# 写列表
def write_csv(file_path):
with open(file_path,'r',newline='') as wcsv_file:
csv_writer = csv.writer(wcsv_file)
csv_writer.writerow(listx)
# 读列表
def read_csv(file_path):
with open(file_path,'r',newline='') as rcsv_file:
csv_reader = csv.reader(rcsv_file) # 读入流一次全部读入
for row in csv_reader: # 循环输出,row实质上是一个列表
print(*row) # 拆包
write_csv(file_path)
read_csv(file_path)
读写字典:
import csv
dictx = {'abc':'XYZ','DEF':154}
file_path = r'b.csv'
# 写字典
def dict_write_csv(file_path):
with open(file_path,'a',newline='') as wcsv_file:
headers = ['abc','DEF'] # 定义一组表头
csv_writer = csv.DictWriter(wcsv_file,headers) # 给定写入流跟表头
csv_writer.writeheader() # 写表头 缺点:每次调用方法都会再次写入表头
csv_writer.writerow(dictx) # 写内容
# 读字典
def dict_read_csv(file_path):
with open(file_path,'r',newline='') as rcsv_file:
csv_reader = csv.DictReader(rcsv_file) # 读入流一次全部读入
for row in csv_reader: # 循环输出,row实质上是OrderedDict
print(dict(row)) # 强转为dict输出
dict_write_csv(file_path)
dict_read_csv(file_path)
序列化和反序列化
每种开发语言都有各自的数据类型,而面向对象的开发语言甚至允许开发者自定义数据类型。开发中常常有如下需求:
- 将内存中各种类型的数据通过网络传递给其他终端或客户端
- 将内存中的各种类型的数据存入本地磁盘实现持久化
序列化和反序列化:
将对象转换为可以通过网络传输或本地存储的数据格式的过程称为 序列化
;反之,称为 反序列化
利用 Json
XML
:可扩展的标签语言,早期使用较多
Json
:JavaScript Object Notation,一种轻量级的数据交换格式,比XML更简单,易于阅读编写以及机器解析与生成;其格式为类似字典的 '{key:value,key:value,key:value}'
的字符串
import json
# 套娃式的一个字典:字典套列表,列表套字典
dictx = {'stuList':
[{'uname':'abc','uid':'1928736'},
{'uname':'def','uid':'6498643'},
{'uname':'ghi','uid':'5925876'}],
'tecList':
[{'uname':'jkl','uid':'x54928731'},
{'uname':'mno','uid':'x18548764'},
{'uname':'pqr','uid':'x15877476'}]}
# 序列化
result1 = json.dumps(dictx) # result1现在是str类型
# 反序列化
result2 = json.loads(result1) # result2现在是dict类型
# 序列化存入文件
with open(r'a.txt','w') as wstream:
json.dump(dictx,wstream)
# 反序列化读出文件
with open(r'a.txt','r') as rstream:
result = json.load(rstream)
content = result.get('stuList')
for stu in content:
print(stu)
利用Pickle
如果要把数据持久化保存至磁盘,这部分数据通常只是供系统内部使用,因此数据转换协议以及之后的数据格式也就不要求是统一的标准的,只要本系统内部能够识别即可。但是系统内部的转换协议通常会随着编程语言版本的升级而发生变化,因此通常会涉及转换协议及编程语言的版本兼容问题
Pickle
:利用Pickle进行序列化返回的是一个 字节串
,反序列化需要传入一个 bytes_object
,因此读写操作都需要添加二进制标志符 b
import pickle
# 套娃式的一个字典:字典套列表,列表套字典
dictx = {'stuList':
[{'uname':'abc','uid':'1928736'},
{'uname':'def','uid':'6498643'},
{'uname':'ghi','uid':'5925876'}],
'tecList':
[{'uname':'jkl','uid':'x54928731'},
{'uname':'mno','uid':'x18548764'},
{'uname':'pqr','uid':'x15877476'}]}
# 序列化
result1 = pickle.dumps(dictx)
# 反序列化
result2 = pickle.loads(result1)
# 对象的序列化与反序列化
import pickle
# 定义一个类
class Stu:
def __init__(self,name,age,cls,tel):
self.name = name
self.age = age
self.cls = cls
self.tel = tel
def __str__(self): # 限制需要序列化的结果
return '{},{},{}'.format(self.name,self.cls,self.tel)
# 生成对象
stu = Stu('xiaohua',18,'G4C187','186-7867-5867')
# 序列化对象并写入文本 注意:要加二进制标志符 b
with open('a.txt','wb') as wstream:
pickle.dump(stu,wstream)
# 从文本中读出并反序列化 注意:要加二进制标志符 b
with open('a.txt','rb') as rstream:
while True:
try:
res = pickle.load(rstream)
print(res)
except:
print('End of File')
break
应用
持久化用户登录及注册信息
利用文件进行持久化。包含用户登录信息的持久化,用户登录信息核对以及不成功重做
# 定义一个用户类
class User:
def __init__(self): # 初始化
self.username = None
self.password = None
def __str__(self): # 限制print输出
return self.username
def login(self): # 登录验证
self.username = input('Please input username:')
self.password = input('Please input password:')
if self.username and self.password:
with open('a.txt', 'r',encoding='utf-8') as rstream: # 打开读流
users_info = rstream.readlines()
for user in users_info:
user = user.replace('\n','') # 读结果预处理
user = user.split(',') # 拆分成列表
username_chk = user[0]
password_chk = user[1]
if self.username == username_chk and self.password == password_chk:
print('登录成功,请继续')
return True # 返回成功标记
else:
continue
else:
print('用户名或密码错误,登陆失败,请重新登录')
return False # 返回失败标记
def register(self):
self.username = input('Please input username:')
self.password = input('Please input password:')
if self.username and self.password:
with open('a.txt', 'a', encoding='utf-8') as wstream:
wstream.write('{},{}\n'.format(self.username, self.password))
print('注册成功!请登录')
return True # 返回成功标记
else:
print('注册不成功,请重新注册')
return False # 返回失败标记
# 封装注册登录流程
def reg_flow():
user = User()
print('请先注册')
reg_flag = True
while reg_flag: # 注册不成功重做注册
reg_flag = not user.register()
print('请登录')
log_flag = True
while log_flag: # 登录不成功重做登录
log_flag = not user.login()
if __name__ == '__main__':
reg_flow()