zoukankan      html  css  js  c++  java
  • Python(3):文件读写与异常

    访问路径:

    文件读写必然涉及到文件会放在某个路径下。在python里,可以通过引入os包来实现切换当前访问的路径:

     1 # 假设我在 /home/zyq/KiDe/Python/test 文件夹中有一个文件 test.txt 那么我可以通过以下命    令定位到该文件夹:
     2 >>>import os
     3 >>>os.chdir('/home/zyq/KiDe/Python/test')
     4 # 此时可以通过 os.getcwd() 来得到当前的工作目录。 
     5 # 此时可以通过如果下命令来进行文件读取测试:
     6 >>>data = open('test.txt')        
     7 >>>print(data.readline(), end='')
     8 This is line1
     9 >>>print(data.readline(), end='')
    10 This is line2
    11 >>>data.seek(0)                        # 此时将游标又放到了文件最开始
    12 >>> for each_line in data:    
    13         print(each_line, end='')
    14 >>>data.close()                        # 一定要记得关闭读取流
    DirRead

    读写实例:

    这里我们来处理另一个类似的文件。只不过这个文件可以看做是两个人对话的文件,文件内容如下:

     1 Man: You didn't!
     2 Other Man:I'm telling you, I did!
     3 Man: You did not!
     4 Other Man:Oh I'am sorry, is this a five minute argument,or the full of the half hour?
     5 Man:Ah!(taking out his wallet and paying) Just the five minutes.
     6 Other Man:Just the five minutes. Thank you.
     7 Other Man:Anyway, I did.
     8 Man:You most certainly did not!
     9 Other Man:Now let's get one thing quite clear:I most definitely old you!
    10 Pause
    11 Man:Oh no you didn't!
    12 Other Man: Oh yes I did!
    13 End
    Talk.txt

    这个文件假设为test2.txt,假设我们需要处理每一行的数据,将每个人的对话区别开来,我们可以使用python内置的split函数, 针对每一行数据采用如下:
    (role, line_spoken) = each_line.split(":")。假设我们以此采用该代码来处理每一行,会发现报了一个:  ValueError:to many values to upack (expected 2) 。这是由于 Other Man:Now let's get one thing quite clear:I most definitely old you! 这一句出现了两个 ":" 。
     
    我们可以通过 help(split)来查看split函数说明,看先是否有可以选择的参数来实现我们所需。

    可以看到有一个 maxsplit参数来指定,对于间隔符的处理次数,我们这里只要得到两部分,即只要处理一次即可,所以可以修改每行读取函数为:

    1 >>>for each_line in data:
    2 >>>    (role, line_spoke) = each_line.split(":", 1)
    3 >>>    print(role, end='')
    4 >>>    print(" says: ", end='')
    5 >>>    print(line_spoke, end='') 
    NewSplit

    这样发现还是有问题,因为 Pause行 和 End行 根本没法进行分割,这时有两种解决方案:

     1 # 方案一: 使用 each_line.find(":")来判断当前行中是否有分割符
     2 >>>for each_line in data:
     3 >>>    if not each_line.find(":") == -1:
     4 >>>        print(role, end='')
     5 >>>           print(" says: ", end='')
     6 >>>        print(line_spoke, end='')
     7 # 这个方案不强壮且可能需要经常变动。此时可以用到异常:
     8 # 方案二: 使用try except来处理,对于异常处理如果使用pass的话表示忽略这个异常继续执行:
     9 >>>for each_line in data:
    10 >>>    try:
    11 >>>        print(role, end='')
    12 >>>           print(" says: ", end='')
    13 >>>        print(line_spoke, end='')        
    14 >>>    except:
    15 >>>        pass 
    Solutions

    可以发现异常只需简单的处理就完成了想要的功能。接下来我们对异常进行具体化,假设要打开的文件不存在,在python中会抛出 IOError 。当然我们也可以通过 if os.path.exists(test3.txt) 来判断文件是否存在。
    这里我们改进下异常处理代码,通过具化的异常捕获来实现:

     1 try:
     2     data = open('test3.txt')
     3     for each_line in data:
     4         (role, line_spoken) = each_line.split(":", 1)
     5         print(role, end='')
     6         print(" says: ", end='')
     7         print(line_spoken, end='')
     8 except ValueError:
     9     pass           # 表示忽略该异常,程序继续往下运行
    10 except IOError:
    11     print("File not exists!")
    12 finally:
    13     if 'data' in locals():                # 判断data变量是否存在当前区域内
    14         print("Close file!")
    15         data.close() 
    SpecificExcept

    保存数据到文件:
    去掉字符串两端的空格,python有一个 strip函数,使用方式和java的trim一样。
    python将数据写入文件大概包括下面三步:
    1. 利用open函数打开文件进行写,open默认的打开方式是 "r",表示文件是用来打开读的,要用来写可以使用 out = open("test2.txt", "w") 。
    2. 利用print函数的file参数,该参数默认是输出到标准控制台(sys.stdout ,可以引入sys来使用该变量),其实也可以指定文件。使用方式如下:
    print("Hello", file = out)。
    3. 一定要记得关闭文件输入流。
    PS: 打开文件进行写的时候,如果文件不存在会自动创建,使用w模式会清空文件中的所有内容。如果想在原来文件内容上追加,可以使用a模式(如果又想读使用a+)。要打开一个文件用来读和写需要清除原来内容的话,使用w+。
    修改前面的分别提取两人的代码,将两个人的说话内容分别写入不同的文件,总的代码如下:

     1 import os
     2 os.chdir('/home/zyq/KiDe/Python/test')
     3 man = []
     4 otherMan = []
     5 try:
     6     data = open('test2.txt')
     7     for each_line in data:
     8         (role, line_spoken) = each_line.split(":", 1)
     9         #print(role, end='')
    10         # Store the message to array by the man
    11         line_spoken = line_spoken.strip()
    12         if role == 'Man':
    13             man.append(line_spoken)
    14         else:
    15             otherMan.append(line_spoken)  
    16         #print(" says: ", end='')
    17         #print(line_spoken, end='')
    18 except ValueError:
    19     pass
    20 except IOError:
    21     print("File not exists!")
    22 finally:                            # 必定会执行的
    23     if 'data' in locals():      # 判断data变量是否存在,即是否打开了文件流
    24         print("Close file test2.txt!")
    25         data.close()
    26  
    27 #write two arrays to file
    28 try:
    29     out1 = open("man.txt", "w")
    30     out2 = open("otherMan.txt", "w")
    31     
    32     print(man, file = out1)
    33     print(otherMan, file = out2)
    34 
    35 except IOError:
    36     print("File write error!")
    37 finally:
    38     out1.close()
    39     print("Close file man.txt!")
    40     out2.close()
    41     print("Close file otherMan.txt!")  
    Write

    PS:在python中的字符串和java中一样也是不可变的。
    上面这个程序还有以下改进点:
    1. 具体的异常信息没有被输出, 这里可以对except块进行改进,改进后方式大致如下:
    except IOError as err:
        print("File error:" + str(err))        # 一定要是用str函数将异常转换为字符串,否则会抛出类型不兼容错误
    2. 对于上面打开的文件,都需要在finally块中将其关闭,其实python实现了jdk1.7之后才有的由编译器自动关闭的方式,通过with方式可以简单的实现该功能:
    with open('test.txt', "w") as data
    另外with支持同时打开多个文件,只需要用逗号隔开即可:
     with open('test.txt', "w") as data, open('test2.txt', "w") as data2
    基于以上两点改进之后,新的代码如下:

     1 import os
     2 os.chdir('/home/zyq/KiDe/Python/test')
     3 man = []
     4 otherMan = []
     5 try:
     6     with open('test2.txt') as data:           # with打开的不需要显示的关闭
     7         for each_line in data:
     8             (role, line_spoken) = each_line.split(":", 1)
     9             # Store the message to array by the man
    10             line_spoken = line_spoken.strip()
    11             if role == 'Man':
    12                 man.append(line_spoken)
    13             else:
    14                 otherMan.append(line_spoken)  
    15 except ValueError:
    16     pass
    17 except IOError as err:
    18     print("File read error:" + str(err))        # 输出具体异常信息
    19  
    20 #write two arrays to file
    21 try:
    22     with open("man.txt", "w") as out1, open("otherMan.txt", "w") as out2:
    23         print(man, file = out1)
    24         print(otherMan, file = out2)
    25 except IOError as err:
    26     print("File write error:" + str(err)) 
    AutoClose

    假设我现在想从文件中读出数据,直接使用readline可以发现文件中的所有内容都会被一股脑的输出出来,当然这时我们可以改进前面的print_list函数,使其增加一个输出到的位置参数 。使当时写入文件的列表数据按行来拆分。但是这样会导致函数的参数越来越多,使用更加复杂。所以这里我们使用另外一种方式: 引入pickle(腌制)包,并使用dump来写入数据,load来读出数据。此时需要注意写入和读出数据的时候模式应该用 "wb" 和 "rb",表示使用二进制的方式。使用pickle的时候可能抛出异常为PickleError,最终我们将代码改为:

     1 import os
     2 import pickle
     3 os.chdir('/home/zyq/KiDe/Python/test')
     4 man = []
     5 otherMan = []
     6 try:
     7     with open('test2.txt') as data:
     8         for each_line in data:
     9             (role, line_spoken) = each_line.split(":", 1)
    10             # Store the message to array by the man
    11             line_spoken = line_spoken.strip()
    12             if role == 'Man':
    13                 man.append(line_spoken)
    14             else:
    15                 otherMan.append(line_spoken)  
    16 except ValueError:
    17     pass
    18 except IOError as err:
    19     print("File read error:" + str(err))
    20  
    21 #write two arrays to file
    22 try:
    23     with open("man.txt", "wb") as out1, open("otherMan.txt", "wb") as out2:
    24         pickle.dump(man, file = out1)
    25         pickle.dump(otherMan, file = out2)
    26 except IOError as err:
    27     print("File write error:" + str(err))
    28  
    29 # 此时如果想读取man.txt文件中的信息的话,只需使用:
    30 import pickle
    31 with open('man.txt', 'rb') as data:
    32     list = pickle.load(data)
    33 # 此时list就是原来的列表。可以直接通过list[0]、list[1] 等来访问列表中的对应项。
    Pickle
  • 相关阅读:
    第3次实践作业
    第2次实践作业
    第09组 团队Git现场编程实战
    第二次结对编程作业
    团队项目-需求分析报告
    团队项目-选题报告
    第一次结对编程作业
    第一次个人编程作业
    第一次博客作业
    课程设计第十四天
  • 原文地址:https://www.cnblogs.com/Kidezyq/p/5772281.html
Copyright © 2011-2022 走看看