我们先处理数据,看看谁对谁说了什么。
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 datafile is missing!')
print(man)
print(other)
str.strip([chars])——strip() 方法用于移除字符串头尾指定的字符(默认为空格)。与java类似。
其中的elif为else if的简写。
得到man和otherman说的话后,我们想将他们的话分别存到两个文件中,这个时候就需要写操作了。
使用open()BIF打开磁盘文件时,可以制定使用什么模式访问。默认地,open()使用模式r表示读,所以不需要专门制定r模式。要打开一个文件完成写,需要使用模式w。
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 datafile is missing!')
try:
man_file = open('man_data.txt', 'w')
other_file = open('other_data.txt', 'w')
print(man, file=man_file)
print(other, file=other_file)
except IOError:
print('File error.')
finally:
man_file.close()
other_file.close()
可以看到
man_file = open(‘man_data.txt’, ‘w’)中,man_file是数据文件对象,‘man_data.txt’是所写文件的文件名,w代表写模式。
默认地,print()BIF显示数据时会使用标准输出(通常是屏幕).要把数据写至一个文件,需要使用file参数来指定所使用的数据文件对象:
print(man, file=man_file),其中man表示写至文件的内容,man_file表示所写数据文件对象。file参数控制将数据发送/保存到哪里。
完成工作时记得close,确保所有数据都写至磁盘,这成为刷新输出(flushing)。这一点和java的I/O流是一样的。
可以发现,这里使用了try/except/finally机制,类似于java中的try/catch/finally,无论有无捕捉到异常,finally中的代码都会执行,这就确保了文件关闭代码一定执行,减少了数据破坏错误的可能性。
运行时出现一个错误时,Python会产生一个特定类型的异常(如IOError,ValueError等)。另外,Python会创建一个异常对象,它会作为一个参数参入except代码组。
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()
在这里,我们尝试打开一个并不存在的文件missing.txt,此时Python解析器会返回error。
except IOError as err:
print(‘File error’+str(err))
产生一个异常并有except组处理时,Python解释器将一个异常对象传入这个except组,并使用as关键字赋至一个标识符。这一点和java中的catch(IOException e)是十分相似的。
而str()方法将异常对象转换(或强制转换)为字符串。
同时,我们看到finally中,locals()BIF会返回当前作用域中定义的所有名的一个集合。如果data在这个集合中时,才会调用close()。
由于处理文件时try/except/finally模式相当常用,所以Python提供了一个语句来抽象出相关的一些细节。对文件使用with语句时,可以大大减少编写的代码量。因为有了with语句就不再需要包含一个finally组来处理文件的关闭,即妥善关闭一个可能打开的数据文件。
来看下面例子:
使用try/except/finally模式
try:
man_file = open('man_data.txt', 'w')
other_file = open('other_data.txt', 'w')
print(man, file=man_file)
print(other, file=other_file)
except IOError as err:
print('File error.'+str(err))
finally:
if 'man_file' in locals():
man_file.close()
if 'other_file' in locals():
other_file.close()
使用with语句
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))
还可以合并到一个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))
使用with时,不再需要操心关闭打开的文件,因为Python解释器会自动为你考虑这一点。with语句利用了一种名为上下文管理协议(context management protocol)的Python技术。
这里我们可以使用前面创建的print_lol()函数,来将数据项一行一行的输出。
需要对该函数进行改动:
import sys
def print_lol(the_list,indent=False,level=0,fh=sys.stdout):
for each_item in the_list:
if isinstance(each_item,list):
print_lol(each_item,indent,level+1,fh)
else:
if indent:
for tab_stop in range(level):
print("\t",end='',file=fh)
print(each_item,file=fh)
标准输出(standard output)这是使用”print()”BIF时代码写数据的默认位置。这通常是屏幕。在Python中,标准输出是指”sys.stdout”,可以从标准库的”sys”模块导入。
第二个参数indent控制是否显示在屏幕上,默认是False。
第三个参数level(默认值为0)用来判断是否嵌套。
第四个参数fh=sys.stdout,用来标识将把数据写入哪个位置。一定要为这个参数提供一个缺省值sys.stdout,这样如果调用这个函数时没有只id那个文件对象则会依然写至屏幕。
而输出数据到文件的代码改为:
import nester
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 datafile is missing!')
try:
with open('man_data.txt','w') as man_file,open('other_data.txt','w') as other_file:
nester.print_lol(man, fh=man_file)
nester.print_lol(other, fh=other_file)
except IOError as err:
print('File error.'+str(err))
使用pikcle的通用文件I/O才是上策
Python提供了一个标准库,名为pickle(腌制),.它可以保存和加载几乎任何Python数据对象,包括列表。
一旦把数据”腌制”到一个文件,它将会永久存储,可以在以后某个日期/时间读入另外一个程序。当然,也可以把”腌制”的数据存储到磁盘上,放在数据库中,或者通过网络传到另外一台计算机中。
将这个过程反过来,将持久存储的腌制数据解除腌制,在Python的内存中庸原来的形式重新创建数据。
腌制
将数据对象保存到一个持久存储中的过程。
解除腌制
从持久存储中恢复一个已保存的数据对象的过程。
使用pickle很简单,只需导入所需的模块pickle,然后使用dump保存数据,以后某个时间使用load()回复数据。处理腌制数据的唯一要求是,必须以二进制访问模式打开这些文件。
pickle.dump()函数将数据保存到磁盘。
pickle.load()函数从磁盘恢复数据。
import pickle
man = []
other = []
try:
data = open('sketch.txt')
for each_line in data:
try:
(role, line_spoken) = each_line.split(':')
line_spoken = line_spoken.strip()
if role == 'Man':
man.append(line_spoken)
elif role == 'Other Man':
other.append(line_spoken)
else:
pass
except ValueError:
pass
data.close()
except IOError:
print('The datafile is missing!')
try:
with open('man_data.txt', 'wb') as man_file, open('other_data.txt', 'wb') as other_file:
pickle.dump(man, file=man_file)
pickle.dump(other, file=other_file)
except IOError as err:
print('File error: ' + str(err))
except pickle.PickleError as perr:
print('Pickling error: ' + str(perr))
可以发现open的模式为wb,其中w代表写,b表示Python以二进制打开数据文件。
pickle.dump(man, file=man_file)——用dump保存man到man_file对象中。
腌制或者解除数据时如果出现错误,pickle模块会产生一个PickleError类型的异常。
打开文件后发现存储的看起来是乱码
Python为了更高效完成腌制,pickle模块使用了一种定制的二进制格式(这称为它的协议)。
要想得到原本数据,需要解除腌制,这个时候要使用pickle.load()
这里open模式为rb
注意,访问列表的最后一个数据项,下标应该为-1.
不难发现,pickle和java中的字节输入输出流是相似的。