在Python中实现文件的读写操作其实非常简单,通过Python内置的函数,我们可以指定文件名、操作模式、编码信息等来获得操作文件的对象,接下来就可以对文件进行读写操作了。这里所说的操作模式是指要打开什么样的文件(字符文件还是二进制文件)以及做什么样的操作(读、写还是追加),具体的如下表所示。

    下面这张图来自于网站,它展示了如果根据应用程序的需要来设置操作模式。

    读取文本文件时,需要在使用open函数时指定好带路径的文件名(可以使用相对路径或绝对路径)并将文件模式设置为'r'(如果不指定,默认值也是'r'),然后通过encoding参数指定编码(如果不指定,默认值是None,那么在读取文件时使用的是操作系统默认的编码),如果不能保证保存文件时使用的编码方式与encoding参数指定的编码方式是一致的,那么就可能因无法解码字符而导致读取失败。下面的例子演示了如何读取一个纯文本文件。

    1. def main():
    2. f = None
    3. try:
    4. f = open('致橡树.txt', 'r', encoding='utf-8')
    5. print(f.read())
    6. except FileNotFoundError:
    7. print('无法打开指定的文件!')
    8. except LookupError:
    9. print('指定了未知的编码!')
    10. except UnicodeDecodeError:
    11. print('读取文件时解码错误!')
    12. finally:
    13. if f:
    14. f.close()
    15. if __name__ == '__main__':
    16. main()

    在Python中,我们可以将那些在运行时可能会出现状况的代码放在try代码块中,在try代码块的后面可以跟上一个或多个except来捕获可能出现的异常状况。例如在上面读取文件的过程中,文件找不到会引发FileNotFoundError,指定了未知的编码会引发LookupError,而如果读取文件时无法按指定方式解码会引发UnicodeDecodeError,我们在try后面跟上了三个except分别处理这三种不同的异常状况。最后我们使用finally代码块来关闭打开的文件,释放掉程序中获取的外部资源,由于finally块的代码不论程序正常还是异常都会执行到(甚至是调用了sys模块的exit函数退出Python环境,finally块都会被执行,因为exit函数实质上是引发了SystemExit异常),因此我们通常把finally块称为“总是执行代码块”,它最适合用来做释放外部资源的操作。如果不愿意在finally代码块中关闭文件对象释放资源,也可以使用上下文语法,通过with关键字指定文件对象的上下文环境并在离开上下文环境时自动释放文件资源,代码如下所示。

    1. def main():
    2. try:
    3. with open('致橡树.txt', 'r', encoding='utf-8') as f:
    4. print(f.read())
    5. except FileNotFoundError:
    6. except LookupError:
    7. print('指定了未知的编码!')
    8. except UnicodeDecodeError:
    9. print('读取文件时解码错误!')
    10. if __name__ == '__main__':
    11. main()

    除了使用文件对象的read方法读取文件之外,还可以使用for-in循环逐行读取或者用readlines方法将文件按行读取到一个列表容器中,代码如下所示。

    要将文本信息写入文件文件也非常简单,在使用open函数时指定好文件名并将文件模式设置为'w'即可。注意如果需要对文件内容进行追加式写入,应该将模式设置为'a'。如果要写入的文件不存在会自动创建文件而不是引发异常。下面的例子演示了如何将1-9999之间的素数分别写入三个文件中(1-99之间的素数保存在a.txt中,100-999之间的素数保存在b.txt中,1000-9999之间的素数保存在c.txt中)。

    1. from math import sqrt
    2. def is_prime(n):
    3. """判断素数的函数"""
    4. assert n > 0
    5. for factor in range(2, int(sqrt(n)) + 1):
    6. return False
    7. return True if n != 1 else False
    8. def main():
    9. filenames = ('a.txt', 'b.txt', 'c.txt')
    10. fs_list = []
    11. try:
    12. for filename in filenames:
    13. fs_list.append(open(filename, 'w', encoding='utf-8'))
    14. for number in range(1, 10000):
    15. if is_prime(number):
    16. if number < 100:
    17. fs_list[0].write(str(number) + '\n')
    18. elif number < 1000:
    19. fs_list[1].write(str(number) + '\n')
    20. else:
    21. fs_list[2].write(str(number) + '\n')
    22. except IOError as ex:
    23. print(ex)
    24. print('写文件时发生错误!')
    25. finally:
    26. for fs in fs_list:
    27. fs.close()
    28. print('操作完成!')
    29. if __name__ == '__main__':
    30. main()

    知道了如何读写文本文件要读写二进制文件也就很简单了,下面的代码实现了复制图片文件的功能。

    1. def main():
    2. try:
    3. data = fs1.read()
    4. print(type(data)) # <class 'bytes'>
    5. with open('吉多.jpg', 'wb') as fs2:
    6. fs2.write(data)
    7. except FileNotFoundError as e:
    8. print('指定的文件无法打开.')
    9. except IOError as e:
    10. print('读写文件时出现错误.')
    11. print('程序执行结束.')
    12. if __name__ == '__main__':
    13. main()

    可能大家已经注意到了,上面的JSON跟Python中的字典其实是一样一样的,事实上JSON的数据类型和Python的数据类型是很容易找到对应关系的,如下面两张表所示。

    我们使用Python中的json模块就可以将字典或列表以JSON格式保存到文件中,代码如下所示。

    1. import json
    2. def main():
    3. mydict = {
    4. 'name': '骆昊',
    5. 'age': 38,
    6. 'qq': 957658,
    7. 'friends': ['王大锤', '白元芳'],
    8. 'cars': [
    9. {'brand': 'BYD', 'max_speed': 180},
    10. {'brand': 'Audi', 'max_speed': 280},
    11. {'brand': 'Benz', 'max_speed': 320}
    12. ]
    13. }
    14. try:
    15. with open('data.json', 'w', encoding='utf-8') as fs:
    16. json.dump(mydict, fs)
    17. except IOError as e:
    18. print(e)
    19. print('保存数据完成!')
    20. if __name__ == '__main__':
    21. main()

    json模块主要有四个比较重要的函数,分别是:

    • dump - 将Python对象按照JSON格式序列化到文件中
    • dumps - 将Python对象处理成JSON格式的字符串
    • load - 将文件中的JSON数据反序列化成对象
    • loads - 将字符串的内容反序列化成Python对象

    这里出现了两个概念,一个叫序列化,一个叫反序列化。自由的百科全书维基百科上对这两个概念是这样解释的:“序列化(serialization)在计算机科学的数据处理中,是指将数据结构或对象状态转换为可以存储或传输的形式,这样在需要的时候能够恢复到原先的状态,而且通过序列化的数据重新获取字节时,可以利用这些字节来产生原始对象的副本(拷贝)。与这个过程相反的动作,即从一系列字节中提取数据结构的操作,就是反序列化(deserialization)”。

    1. import requests
    2. import json
    3. def main():
    4. resp = requests.get('http://api.tianapi.com/guonei/?key=APIKey&num=10')
    5. data_model = json.loads(resp.text)
    6. for news in data_model['newslist']:
    7. print(news['title'])
    8. main()

    在Python中要实现序列化和反序列化除了使用json模块之外,还可以使用pickle和shelve模块,但是这两个模块是使用特有的序列化协议来序列化数据,因此序列化后的数据只能被Python识别。关于这两个模块的相关知识可以自己看看网络上的资料。另外,如果要了解更多的关于Python异常机制的知识,可以看看segmentfault上面的文章,这篇文章不仅介绍了Python中异常机制的使用,还总结了一系列的最佳实践,很值得一读。