持久存储的含义:将基于内存的数据存储在磁盘上
通常情况下,程序会保存所处理的数据,将输出显示在屏幕上,或者通过网络传输数据
持久存储的第一步——生成一些值得保存的数据
import os
os.getcwd()
os.chdir('C:/Users/0AQZ0/Documents/exercisecode/Python/HeadFirstPython/chapter3')
os.getcwd()
man = []
other = []
try:
data = open('sketch.txt')
for each_line in data:
try:
(role, line_spoken) = each_line.split(':', 1)
line_spoken = line_spoken.strip() #将去除空白符后的字符串再赋回到自身
if role == 'Man':
man.append(line_spoken)
elif role == 'Other Man':
other.append(line_spoken)
except ValueError:
pass
data.close()
except IOError:
print('The data file is missing')
print(man)
print(other)
strip()方法从字符串中去除不想要的空白符
elif表示else if
生成的数据:
>>>
['Is this the right room for an argument?', "No you haven't!", 'When?', "No you didn't!", "You didn't!", 'You did not!', 'Ah! (taking out his wallet and paying) Just the five minutes.', 'You most certainly did not!', "Oh no you didn't!", "Oh no you didn't!", "Oh look, this isn't an argument!", "No it isn't!", "It's just contradiction!", 'It IS!', 'You just contradicted me!', 'You DID!', 'You did just then!', '(exasperated) Oh, this is futile!!', 'Yes it is!']
["I've told you once.", 'Yes I have.', 'Just now.', 'Yes I did!', "I'm telling you, I did!", "Oh I'm sorry, is this a five minute argument, or the full half hour?", 'Just the five minutes. Thank you.', 'Anyway, I did.', "Now let's get one thing quite clear: I most definitely told you!", 'Oh yes I did!', 'Oh yes I did!', 'Yes it is!', "No it isn't!", 'It is NOT!', "No I didn't!", 'No no no!', 'Nonsense!', "No it isn't!"]
Python的open() BIF除了可以打开文件来读文件,也可以写文件
使用open() BIF打开磁盘文件时,可以指定使用什么访问模式。默认地,open()使用模式r表示读,所以不需要专门指定r模式
要打开一个文件完成写,需要使用模式w:
out = open("data.out", "w")
“w”:要使用的访问模式
“out”:数据文件对象
“data”:所写文件的文件名
默认地,print() BIF显示数据时会使用标准输出(通常是屏幕)
要把数据写至一个文件,需要使用file参数来指定所使用的数据文件对象:
print("Norwegian Blues stun easily.", file=out)
“out”:所写数据文件对象的名
完成工作时,一定要关闭文件,确保数据都写至磁盘。这称为刷新输出(flushing)
out.close()
使用模式w访问文件时,如果这个文件已经存在,则会清空它现有的内容。如果要追加到一个文件,需要使用访问模式a。要打开一个文件来完成读和写(不清除),需要使用w+。如果文件不存在,则会创建一个新文件
我的代码:
import os
os.getcwd()
os.chdir('C:/Users/0AQZ0/Documents/exercisecode/Python/HeadFirstPython/chapter4')
os.getcwd()
man = []
other = []
try:
data = open('sketch.txt')
for each_line in data:
try:
(role, line_spoken) = each_line.split(':', 1)
line_spoken = line_spoken.strip()
if role == 'Man':
man.append(line_spoken)
elif role == 'Other Man':
other.append(line_spoken)
except ValueError:
pass
data.close()
except IOError:
print('The data file is missing')
try:
out1 = open("man_data.txt", "w")
out2 = open("other_data.txt", "w")
print(man, file=out1)
print(other, file=out2)
out1.close()
out2.close()
except:
print("IOError")
发生异常后文件保持打开
如果从文件中读取数据,得到一个IOError还不算危险,因为数据还在文件中
如果向文件中写数据,在文件关闭前处理一个IOError,所写的数据可能会被破坏
解决方法:finally组
不论出现什么错误都必须运行某些代码时,可以向try语句的finally组增加代码
try:
out1 = open("man_data.txt", "w")
out2 = open("other_data.txt", "w")
print(man, file=out1)
print(other, file=out2)
except:
print("IOError")
finally:
out1.close()
out2.close()
把close()调用移到finally组中
如果试图打开一个不存在的文件
>>> try:
data = open('missing.txt')
print(data.readline(), end='')
except IOError:
print('File Error')
finally:
data.close()
File Error
Traceback (most recent call last):
File "" , line 7, in
data.close()
NameError: name 'data' is not defined
由于数据文件对象并未创建,所以无法调用close()方法,导致一个NameError错误。解决方法:使用locals()
BIF增加一组测试
locals() BIF会返回当前作用域中定义的所有名的集合
>>> try:
data = open('missing.txt')
print(data.readline(), end='')
except IOError:
print('File Error')
finally:
if 'data' in locals():
data.close()
File Error
产生一个异常并由except组处理时,Python解释器会将一个异常对象传入except组
为异常对象定一个标识符就可以使用它
>>> try:
data = open('missing.txt')
print(data.readline(), end='')
except IOError as err:
print('File Error:' + err)
finally:
if 'data' in locals():
data.close()
Traceback (most recent call last):
File "" , line 2, in
data = open('missing.txt')
FileNotFoundError: [Errno 2] No such file or directory: 'missing.txt'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "" , line 5, in
print('File Error:' + err)
TypeError: Can't convert 'FileNotFoundError' object to str implicitly
由于异常对象和字符串类型不兼容,所以出现TypeError
可以使用str()
BIF将异常对象转换为字符串
>>> try:
data = open('missing.txt')
print(data.readline(), end='')
except IOError as err:
print('File Error:' + str(err))
finally:
if 'data' in locals():
data.close()
File Error:[Errno 2] No such file or directory: 'missing.txt'
对文件使用with语句,可以大大减少需要编写的代码量
使用with时,不再需要操心关闭打开的文件,因为Python解释器会自动为你考虑
try:
data = open('its.txt')
print("It's ...", file=data)
except IOError as err:
print('File Error:' + str(err))
finally:
if 'data' in locals():
data.close()
等效于
try:
with open('missing.txt') as data:
print("It's ...", file=data)
except IOError as err:
print('File Error:' + str(err))
with语句利用了一种名为上下文管理协议(context management protocol)的技术
我的代码:
try:
with open("man_data.txt", "w") as man_file:
print(man, file=man_file)
with open("other_data.txt", "w") as other_file:
print(other, file=other_file)
except IOError as err:
print("File Error:" + str(err))
可以将两个open()调用合并到一个with语句中
try:
with open("man_data.txt", "w") as man_file, open("other_data.txt", "w") as other_file:
print(man, file=man_file)
print(other, file=other_file)
except IOError as err:
print("File Error:" + str(err))
把数据保存在数据文件之前应先对数据格式化,这样可以采用一种更可用的格式保存数据
修改print_lol()函数,让它把数据输出到磁盘文件而不是屏幕上(标准输出)
标准输出:使用print() BIF时代码写数据的默认位置,通常是屏幕。在Python中,标准输出是指“sys.stdout”,可以从标准库的“sys”模块导入
修改后的print_lol()函数:
import sys
def print_lol(the_list, indent=False, level=0, out=sys.stdout):
for each_item in the_list:
if isinstance(each_item, list):
print_lol(each_item, indent, level+1, out)
else:
if indent:
for num in range(level):
print("\t", end='', file=out)
print(each_item, file=out)
修改后的with语句:
with open("man_data.txt", "w") as man_file, open("other_data.txt", "w") as other_file:
nester5.print_lol(man, out=man_file)
nester5.print_lol(other, out=other_file)
Python提供了一个标准库,名为pickle,它可以加载和保存几乎任何Python数据对象,包括列表
一旦把数据“腌制”到一个文件,它将会持久存储,“腌制”的数据可以存储在磁盘上、数据库中,或者通过网络传输到另一个计算机
将这个过程反过来,可以将持久存储的数据解除腌制,在Python的内存中用原来的形式重新创建数据
如何使用pickle?
唯一要求:必须以二进制访问模式打开这些文件
示例:
import pickle
...
with open('mydata.pickle', 'wb') as mysavedata:
pickle.dump([1, 2, 'three'], mysavedata)
...
with open('mydata.pickle', 'rb') as myrestoredata:
a_list = pickle.load(myrestoredata)
print(a_list)
“b”告诉Python以二进制模式打开数据文件
如果腌制或者解除数据腌制时出问题,pickle模块会产生一个PickleError类
型的异常
我的代码:
import pickle
try:
with open("man_data.txt", "wb") as man_file, open("other_data.txt", "wb") as other_file:
pickle.dump(man, man_file)
pickle.dump(other, other_file)
except IOError as err:
print("File Error:" + str(err))
except pickle.PickleError as perr:
print("Pickling Error:" + str(perr))
联合nester模块使用pickle模块:
>>> import pickle
>>> import nester5
>>> new_man = []
>>> try:
with open('man_data.txt', 'rb') as man_file:
new_man = pickle.load(man_file)
except IOError as err:
print("File Error: " + str(err))
except pickle.PickleError as perr:
print("Pickling Error: " + str(perr))
>>> nester5.print_lol(new_man)
Is this the right room for an argument?
...
Yes it is!
>>> print(new_man[0])
Is this the right room for an argument?
>>> print(new_man[-1])
Yes it is!
使用pickle的通用文件I/O才是上策