2.1 使用Python的open函数操作文件
使用Python的open函数可以对文本文件和二进制文件进行只读、只写、读/写和追加等操作。
2.1.1 open函数
Python的open函数按指定模式打开一个文件,并返回file对象。该函数的语法格式为:
其中,各参数的含义如下。
• file:必需参数,指定文件路径和名称。
• mode:可选参数,指定文件打开模式,包括读、写、追加等各种模式。
• buffering:可选参数,设置缓冲(不影响结果)。
• encoding:可选参数,设置编码方式,一般使用UTF-8。
• errors:可选参数,指定当编码和解码错误时怎么处理,适用于文本模式。
• newline:可选参数,指定在文本模式下控制一行结束的字符。
• closefd:可选参数,指定传入的file参数类型。
• opener:可选参数,设置自定义文件打开方式,默认时为None。
注意:使用open函数打开文件操作完毕后,一定要保证关闭文件对象。关闭文件对象使用close函数。
使用open函数打开文件后会返回一个file对象,利用该对象的方法可以进行文件内容的读取、写入、截取和文件关闭等一系列操作,如表2-1所示。
表2-1 file对象的方法
2.1.2 创建文本文件并写入数据
当使用open函数打开文件时,如果指定mode参数的值为表2-2中的值,若文件不存在,则会创建新文件。
表2-2 写入文本文件时mode参数的设置
例如,下面创建一个文本文件filetest.txt,放在D盘下。
open函数返回一个file对象,使用该对象的write方法向文件中写入数据。
返回值13表示文件中字节的长度。
现在打开D盘下的filetest.txt文件,会发现什么内容也没有。使用file对象的close方法关闭文件对象。
现在打开该文件,发现刚刚写入的字符串"Hello Python!"显示出来了,如图2-1所示。
图2-1 创建文本文件并写入数据
使用open函数打开D盘下已经存在的filetest.txt文件,模式为“w”,然后使用file对象的write方法写入一个新的字符串,最后关闭文件对象。
打开文件,显示效果如图2-2所示。
图2-2 打开文件重新写入数据
这说明在“w”模式下,当打开已经存在的文件并重新写入数据时,文件中原来的数据会被删除。
下面使用with语句打开文本文件后写入数据。使用这种方法的好处是执行完后会主动关闭文件,不需要使用file对象的close方法进行关闭。
打开文件,发现文件原来的内容被删除,重新写入了"Hello Python!"。
使用file对象的writelines方法,可以用列表结合换行符一次写入多行数据。
打开文件,发现列表中的两个元素数据已经分两行写入。
下面打开文本文件后使用循环连续写入数据。其中,“\r”表示回车,“\n”表示换行。
打开文件,发现已经连续写入了10行"Hello Python!"。
2.1.3 读取文本文件数据
当使用open函数打开文件时,如果指定mode参数的值为表2-3中的值,则读取文件的内容。
表2-3 读取文本文件时mode参数的设置
2.1.2节最后使用一个for循环向D盘下的filetest.txt文件中写入了10行数据。下面使用open函数打开该文件,将mode参数的值设置为“r”,只读。然后使用file对象的read方法读取文件的内容。
下面使用file对象的write方法向文件中写入数据。
可见,因为打开文件时设置mode参数为“r”,只读,所以试图向文件中写入数据时报错。
下面使用file对象的readline方法逐行读取数据。
读取第1行数据:
读取第2行数据,是一个空行:
读取第3行数据的前5个字符:
下面使用file对象的readlines方法读取所有行数据。
2.1.4 向文本文件中追加数据
当使用open函数打开已经存在的文件时,如果指定mode参数的值为表2-4中的值,则可以在原有内容后面追加数据,即原来的数据保留,继续追加数据。
表2-4 向文本文件中追加数据时mode参数的设置
下面打开D盘下的filetest.txt文件,设置mode参数的值为“a”。
添加新行:
打开该文本文件,可以看到在原有内容的后面添加了新行数据,原有内容仍然保留。
2.1.5 读/写二进制文件数据
本章前面各节介绍了使用Python的open函数实现文本文件数据读/写的方法,使用该函数还可以进行二进制文件数据的读/写。很多图形、图像和视频文件都采用二进制格式读/写数据。
在实现时只需要修改mode参数的值即可。表2-5中列出了读/写二进制文件时mode参数的设置,可见,这些参数与文本文件设置的基本相同,只是多了一个“b”。“b”是binary,即二进制的意思。
表2-5 读/写二进制文件时mode参数的设置
二进制文件是以字节为单位存储的,所以使用file对象的write方法写入数据时,需要先将数据从字符串转换为字节流,使用bytes函数进行转换,指定编码方式。从二进制文件读取数据时,则需要使用decode方法对read方法读出的数据进行解码,同样要指定编码方式。
下面假设要保存一个直线段图形的数据,包括直线段的起点坐标(10,10)和终点坐标(100,200),保存为D盘下的二进制文件bftest.cad,cad为自定义的扩展名。
现在可以在D盘下找到刚刚创建的二进制文件bftest.cad。
在打开该文件时,需要能获取到先前保存的直线段起点和终点的坐标数据,以便重新绘图。此时使用open函数打开文件时,将mode参数的值设置为“rb”,以二进制格式读取。然后使用file对象的read方法读取数据,该数据不能直接用,还需要使用decode方法以先前保存时指定的编码方式解码得到字符串。最后使用split方法从该字符串中获取直线段起点和终点的坐标数据字符串,并使用int函数将其转换为整型数字。
在得到坐标数据后,就可以使用绘图函数把直线段重新绘制出来了。这就是图形保存和打开的完整过程,实际上是图形控制点数据的保存和打开处理。
2.1.6 使用struct模块读取二进制文件
2.1.5节使用Python的open函数实现了二进制文件的读/写,在使用该方法保存不同类型的数据时需要先将它们转换为字符串,再按照一定的编码方式将字符串转换为字节流进行写入;当从文件中将数据读取出来时则反过来,需要先将读取出来的数据按同样的编码方式解码成字符串,然后从字符串中获取数据。这个过程相对比较烦琐,Python的struct模块对该过程进行了简化,可以比较方便地处理不同类型数据的读/写。
下面使用struct模块处理与2.1.5节相同的直线段数据的二进制文件写入和读取。在使用struct模块前,需要先用import命令导入它。
当使用file对象的write方法写入数据时,使用struct模块的pack函数将坐标数据转换为字符串,然后写入该字符串。该函数的语法格式为:
其中,fmt参数指定数据类型,如整型数字用“i”表示,浮点型数字用“f”表示。按照先后次序,每个数据都要指定数据类型。
现在直线段的坐标数据被保存到D盘下的二进制文件bftest2.cad中了。
在读取数据时,需要使用struct模块的unpack函数进行解包,解包得到的数据以元组方式返回。
与2.1.5节对比,可见,使用struct模块读/写二进制文件比直接使用file对象的方法读/写要方便得多。