(九)数据读入和保存

一、文本文件(*.txt)

Python的open() BIF就是用来与文件交互的,使用时,会创建一个迭代器从文件向代码输入数据行,一次传入一行数据。代码:

the_file=open(‘sketch.txt’)         #打开文件

the_file.close()                  #关闭文件

 

具体的过程:

导入os模块,并把当前工作目录切换到包含刚下载的数据文件的文件夹:

>>> import os

>>> os.getcwd()

'C:\\Python34'

>>>os.chdir("C:/Users/DELL/Desktop/金工/编程/python")

>>> os.getcwd()

'C:\\Users\\DELL\\Desktop\\金工\\编程\\python'

注意:

chdir里面一定是反斜杠”/”,如果从地址栏复制粘贴的地址,一定要改过来

 

 

现在,打开数据文件,从文件读取前两行,并在屏幕上显示出来

>>>data=open('sketch.txt')     #打开一个命名文件,将文件复制一个名为“data”的文件对象

>>>print(data.readline(),end='') #使用“readline()”方法从文件获取一个数据行

#然后使用”print()”BIF在屏幕上显示这个数据行

Man: Is this the right room for anargument?

>>> print(data.readline(),end='')

Other Man: I've told you once.

 

 

下面再“退回”到文件起始位置,然后使用for语句处理文件中的每一行

>>> data.seek(0)  #使用“seek()”方法返回到文件起始位置

0

>>> for each_line in data:  #标准迭代,用文件数据作为输入

         print(each_line,end='')

 

>>> data.close()         #结束关闭文件

 

 

 

二、进一步查看数据

进一步查看数据,看起来遵循某种特定的格式:演员角色,冒号,空格符,台词。

了解这个格式后,可以处理各行数据,歌剧需要抽取出数据行中的各个部分,split()方法可以提供帮助:

each_line.split(“:”)

split()方法返回一个字符串列表,这会复制一个目标标识符列表,这称为多重赋值:

(role,line_spoken)=each_line.split(“:”)

 

 

下面来确认还能处理文件同时分解各行,代码:

>>> data.close()

>>> data=open('sketch.txt')

>>> for each_line in data:

         [role,line_spoken]=each_line.split(':')

         print(role,end='')

         print('said:',end='')

         print(line_spoken,end='')

 

输出时出现了问题:

Traceback (most recent call last):

 File "<pyshell#97>", line 2, in <module>

   [role,line_spoken]=each_line.split(':')

ValueError: too many values to unpack(expected 2)

 

代码刚开始还能正常工作,然后就崩溃了,只是有一个运行时错误,比如说,一行数据有两个冒号,多余的数据导致split()无法正常工作。按目前代码来看,split()要把数据行分为两部分,分别赋给role和line_spoken,数据中出现一个额外的冒号是,split()方法将这一行分为3个部分,你的代码没有告诉split()该如何处理第3部分,所以python解释器会产生一个ValueError,抱怨“值过多”,然后终止。

 

这是,我们可以看看split()方法是否包含对我们有帮助的功能,可以用help() BIF让IDLE shell告诉我们更多有关split()方法的信息

>>> help(each_line.split)

Help on built-in function split:

 

split(...) method of builtins.str instance

   S.split(sep=None, maxsplit=-1) -> list of strings

   

   Return a list of the words in S, using sep as the

   delimiter string.  If maxsplit isgiven, at most maxsplit

   splits are done. If sep is not specified or is None, any

   whitespace string is a separator and empty strings are

removed from theresult.

 

因为有maxsplit,说明split有一个可选参数,控制着将数据行分解为多少部分,如果没有这个参数,默认的,数据会尽可能多的分解。我们只需要两个部分:角色名和讲的台词,如果将这个可选参数设置为1,数据行只会分解为两部分,这实际上就消除了数据行中额外冒号的影响。

>>> for each_line in data:

         [role,line_spoken]=each_line.split(':',1)

         print(role,end='')

         print('said:',end='')

         print(line_spoken,end='')

 

但此时,又出现了错误:

Traceback (most recent call last):

 File "<pyshell#100>", line 2, in <module>

   [role,line_spoken]=each_line.split(':',1)

ValueError: need more than 1 value to unpack

 

这时,有要去反思数据的问题,这次python出问题在于没有足够的数据来处理

 

比如说,有一行是:

(pause)

 

所以,有些数据行不包含冒号,split()方法查找冒号时就会出现问题。

解决方法有两个:一是判断是否可以在数据行上调用split();二是看到错误时以某种方式恢复。下面每种方法都来尝试一下。

 

【增加判断】

 

让find()来尝试找出一个字符串中的子串:如果无法找到,find返回值-1;如果找到,返回该子串在原字符串中的索引位置。

 

上述代码可修改为:

>>> data=open('sketch.txt')

>>> for each_line in data:

         ifnot each_line.find(':')==-1:

                   [role,line_spoken]=each_line.split(':',1)

                   print(role,end='')

                   print('said:',end='')

                   print(line_spoken,end='')

>>> data.close()

 

问题:如果文件的格式改变,代码也需要改变,而更多代码通常意味着更大的复杂性,增加额外代码来处理异常情况的做法确实可行,但长远来看是有代价的。

 

接下来一种方法,就是处理异常。

 

三、处理异常

 

如果python解释器显示traceback,那么后面就会跟着一个错误信息。Python的异常处理机制允许错误出现,但监视它的发生,然后给你一个机会来修复。在正常的控制流期间,python尝试运行你的代码,如果没有任何问题,代码会继续正常执行,如果发现问题,就会执行恢复代码,然后继续正常执行代码。

 

try/except机制

 

try语句的一般形式:

try:

你的代码(可能导致一个运行时错误)

except:

错误恢复代码

 

回到我们之前的例子中,需要保护的代码是split以及之后的print

修改代码为:

>>> data=open('sketch.txt')

>>> for each_line in data:

         try:

                   (role,line_spoken)=each_line.split(':',1)

                   print(role,end='')

                   print('said: ',end='')

                   print(line_spoken,end='')

         except:

                   pass

>>> data.close()

是可以运行的

 

 

那对比来说,哪一种更好呢?

额外代码会通过确保运行时错误不会发生,但要以增加复杂性为代价,而且可能会需要一遍遍调试复杂代码,因为可能会发生意想不到的事。所以楼主更偏向于使用第二种方法,这样只需要提取可以利用的数据就好了。

 

但是如果缺少文件,两种方法都会崩溃,产生一个IOError

 

如果是“增加逻辑判断”一派,那么第一个反应肯定是再增加另外的代码,在尝试打开文件之前先查看数据文件是否存在。以之前的例子为例:

>>> impose os

>>> ifos.path.exists('sketch.txt'):

         data=open('sketch.txt')

         foreach_line in data:

                   ifnot each_line.find(':')==-1:

                            (role,line_spoken)=each_line.split(':',1)

                            print(role,end='')

                            print('said: ',end='')

                            print(line_spoken,end='')

data.close()

  else:

print(‘The datafile is missing!’)

 

如果是增加一层异常处理,那么会把代码包在另一个try语句中。以之前的例子为例:

>>> try:

         data=open('sketch.txt')

         foreach_line in data:

                   try:

                            (role,line_spoken)=each_line.split(':',1)

                            print(role,end='')

                            print('said: ',end='')

                            print(line_spoken,end='')

                   except:

                            pass

         data.close()

except:

         print('Thedata file is missing!')

 

 

有以上可以看出,谨慎使用try语句可以让代码更易读,更易写,而且可能这是最重要的——出问题时更容易修正。

 

 

注:

1、  我们用split()方法执行时,传回一个列表,目标标识符可以在小括号之间,也可以在中括号之间。Python中实际上有两种类型的列表:一种是可以改变的列表(用中括号包围),另一种一旦创建就不能改变(用小括号包围)。后者是一种不可改变列表,更常见的称呼是元组(tuple)。

 

 

四、try的改善

异常处理代码很不错,因为它具有一般性,但是所有的错误都会被忽略,如果在except代码行上制定错误类型,就可以把一般化的异常处理代码转变为具有特定性的。

例:

try:

         data=open('sketch.txt')

         foreach_line in data:

                   try:

                            (role,line_spoken)=each_line.split(':',1)

                            print(role,end='')

                            print('said: ',end='')

                            print(line_spoken,end='')

                   except  ValueError:

                            pass

         data.close()

except IOError:

         print('Thedata file is missing!')

 

五、数据保存

练习:

创建一个空列表,名为man,在创建一个空列表,名为other,增加一行代码,删除line_spoken变量中不需要的空白符,给出条件和代码,根据role的值将line_spoken增加到适当的列表中。最后在屏幕上输出各个列表(man和other)

例:

>>> try:

         data=open('sketch.txt')

         foreach_line in data:

                   try:

                            (role,line_spoken)=each_line.split(':',1);

                            line_spoken=line_spoken.strip();

                            ifrole=='Man':

                                     man.append(line_spoken);

                            elifrole=='Other Man':

                                     other.append(line_spoken);

                   exceptValueError:

                            pass

         data.close()

except IOError:

         print('Thedatafile is missing')

 

>>> print(man)

>>> print(other)

      以写模式打开文件

需要使用模式w:(注:要打开一个文件来完成写和读,需要使用w+)

     out=open(‘data.out’,’w’)

默认地,print()BIF显示数据是会使用标准输出(通常是屏幕)。要把数据写至一个文件,需要使用file参数来指定所使用的数据文件对象:

        print(‘Norwegian Blues stun easily’,file=out)

完成工作时,一定要关闭文件,确保所有数据都写至磁盘。

        out.close()

例:

>>> man=[]

>>> other=[]

>>> try:

         data=open('sketch.txt')

         foreach_line in data:

                   try:

                            (role,line_spoken)=each_line.split(':',1)

                            line_spoken=line_spoken.strip()

                            ifrole=='Man':

                                     man.append(line_spoken)

                            elifrole=='Other Man':

                                     other.append(line_spoken)

                   exceptValueError:

                            pass

         data.close()

except IOError:

         print('Thedatafile is missing')

 

        

>>> out1=open('man.txt','w')

>>> out2=open('other.txt','w')

>>> print(man,file=out1)

>>> print(other,file=out2)

>>> out1.close()

>>> out2.close()

如果其中一个文件有问题,不论出现什么错误都必须运行某些代码时,可以向try语句的finally组增加代码:

           try:

           except:

           finally:

例:

>>> try:

         out1=open('man.txt','w')

         out2=open('other.txt','w')

         print(man,file=out1)

         print(other,file=out2)

except IOError:

         print('Fileerror.')

finally:

         out1.close()

         out2.close()

这样,通过把文件关闭代码移入finally组中,可以减少数据破坏错误的可能性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值