使用Python读写文件遇到的几个问题

不记得我学习Python语法是啥时候的事情,只知道自己现在什么也记不住了。刚好自己有点小需要,就用Python把自己在某个APP上的数据数据拉下来吧!这个过程实在是太爽(can)了~
各种问题我都不想吐槽自己了,就把Python操作文件时遇到的几个问题写写吧。

文件编码

脑子果然是好使,一顿百度、复制和粘贴,代码我算是写完了。但是还都没有运行测试过,鄙人深知后面才真的是任重道运。
我打开Windows PowerShell客户端,洋洋洒洒十几个字母敲下去。先规范了几轮代码格式,终于没有提示格式错误了,也终于提示有真正的Bug了。。。

1
2
3
4
5
6
7
8
9
Z:\WorkSpace\Git\SimpleSpider\BoCai> python.exe .\pull.py
Traceback (most recent call last):
File ".\pull.py", line 248, in <module>
pullAll()
File ".\pull.py", line 246, in pullAll
pullBook(bookId)
File ".\pull.py", line 215, in pullBook
file_object.write(out)
UnicodeEncodeError: 'gbk' codec can't encode character '\U0001f625' in position 73431: illegal multibyte sequence

显然,提示的是内容中存在部分字符无法用“GBK”编码保存,因为Windows系统默认是GBK编码,所以这里在打开文件时需要指定编码格式。然而, open() 函数在Python 2.X和Python 3.X中的定义有区别!

版本区别

作为一个Python菜鸟,我使用 open() 函数时显然一直都没有给它传递过“encoding”参数,而今天我给它传这个参数也是遇到了不少麻烦的事情。
为了操作文件,我们首先要使用 open() 函数将文件打开。在Python 2.X版本中,我们通常会给 open() 函数传递两个参数。

1
2
3
4
5
open(name[, mode[, buffering]])
# 第一个参数name是文件的路径,这里使用绝对路径和相对路径都可以。
# 第二个参数mode是读写的模式,声明的读写模式决定了后续对文件进行操作的权限和方式。
# 第三个参数buffering是缓冲的大小。
# 0——无缓冲(仅二进制文件可用);1——行缓冲(仅文本文件可用);其它正值——参数大小的缓冲;负值——默认缓冲(TTY设备是行缓冲,其它文件全缓冲)。

而在Python 3.X版本中,open() 函数与2.X版本的有较大区别,参数要丰富很多。

1
2
3
4
5
6
7
8
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True)
# 第一个参数file是文件的路径,这里使用绝对路径和相对路径都可以。
# 第二个参数mode是读写的模式,同上,后面会详细说明。
# 第三个参数buffering是缓冲的大小,同上。
# 第四个参数encoding是文件编码,默认是平台相关的编码。
# 第五个参数errors是指定编码和解码错误的处理方式,详情可以查看文档。
# 第六参数newline,回车换行的模式(仅适用于文本模式),可选值有:None, '', '\n', '\r', 和 '\r\n'。
# 第六参数closefd,当给的file是文件描述符时,可以通过这个参数控制关闭文件时是否关闭文件描述符。

如果我们在Python 2.X版本读取文件时,需要使用非系统默认编码,我们可以将读取到的文件内容使用 decode() 函数进行编码:

1
2
3
4
5
6
7
8
9
Z:\WorkSpace\Git\SimpleSpider\BoCai> python.exe
Python 2.7.14 (v2.7.14:84471935ed, Sep 16 2017, 20:19:30) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> print open("./test-gbk.txt","r").read()
测试文档
>>> print open("./test-utf8.txt","r").read()
娴嬭瘯鏂囨。
>>> print open("./test-utf8.txt","r").read().decode("UTF-8")
测试文档

我们除了手动转换编码,还可以使用Python提供的codecs模块帮助我们在读取文件是自动转换编码。

1
2
3
>>> import codecs
>>> print codecs.open("./test-utf8.txt","r","UTF-8").read()
测试文档

对应的写入操作时,我们也需要手动转换编码(以下代码是Windows下Python 2.7命令行模式执行成功)。

1
2
3
4
5
6
7
8
9
10
# 直接写GBK
>>> open("./test-gbk.txt","w+").write("测试文档")
>>> open("./test-gbk.txt","w+").write(unicode("测试文档","gbk").encode("gbk")) #与上述效果一样
>>> open("./test-gbk.txt","w+").write(unicode("测试文档","gbk")) #会出现编码错误
# 手动编码写UTF-8
>>> open("./test-utf8.txt","w+").write(unicode("测试文档","gbk").encode("utf-8"))
# 使用codecs模块写UTF-8
>>> import codecs
>>> codecs.open("./test-utf8.txt","w+","UTF-8").write(unicode("测试文档","gbk"))

读写模式

轻(li)轻(jin)松(jian)松(nan)把编码文件解决了,后面应该不会有啥问题了,开耍吧~
因为要拉取的数据量有点大,我决定把要拉取的内容按时间段切分,还是小范围测试拉取一下看看效果。
果然不负我望,数据拉取没有问题,那就正式开干吧!首先把文件路径改到我常用的目录地下,保存输入命令,回车~
什么,我按回车了?赶紧停止运行,刚才那个目录有一个同名文件存着我的数据呢,还好手速快程序应该没到写入文件的那步。
赶紧打开原来的文件,但我看到的仍然是一片空白。。。

  • 原来我使用的是“W+”模式,即可读可写模式,但是Python在打开文件时就会清空文件内容!!!

Python操作文件的相关模式如下:

模式 说明
r 打开阅读(默认)
w 打开写入,首先截断文件
x 打开独占创建,如果文件已经存在则失败
a 打开写入,追加到文件末尾(如果存在)
b 二进制模式
t 文本模式(默认)
+ 打开磁盘文件进行更新(读取和写入)
U 通用换行符模式(已弃用)

常用组合说明

  • ‘r’——打开只读文件。该文件必须存在。
  • ‘r+’——打开可读写的文件。该文件必须存在,从头开始写,保留原文件中没有被覆盖的内容
  • ‘w’——打开只写文件。若文件存在则文件长度清零,即内容清空。若文件不存在则建立该文件。
  • ‘w+’——打开可读写的文件。若文件存在则文件长度清零,即内容清空。若文件不存在则建立该文件。
  • ‘a’——以追加方式打开只写文件。若文件存在数据会被加到文件尾,若文件不存在则建立该文件。
  • ‘a’+——以追加方式打开可读写的文件。若文件存在数据会被加到文件尾,若文件不存在则建立该文件。
  • 对于二进制读写访问,’w+b’打开并将文件清零。 ‘r+b’不清零打开文件。

初学Python,上述表述可能会存在一定问题,恳请大家发现问题后及时指正,以免误导其他人!谢谢!
阅读官方文档Python 2/Python 3,了解更多!