Python初入门(四)(Head First Python 第四章 数据保存到文件)

程序生成数据

我们先处理数据,看看谁对谁说了什么。

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()。


用with处理文件

由于处理文件时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))



这时可以看到输出是符合我们的要求了Python初入门(四)(Head First Python 第四章 数据保存到文件)_第1张图片


腌制数据

使用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()
Python初入门(四)(Head First Python 第四章 数据保存到文件)_第2张图片
这里open模式为rb

注意,访问列表的最后一个数据项,下标应该为-1.

不难发现,pickle和java中的字节输入输出流是相似的。

你可能感兴趣的:(Python)