![代替VBA!用Python轻松实现Excel编程](https://wfqqreader-1252317822.image.myqcloud.com/cover/254/43738254/b_43738254.jpg)
2.1 使用Python的open函数操作文件
使用Python的open函数可以对文本文件和二进制文件进行只读、只写、读/写和追加等操作。
2.1.1 open函数
Python的open函数按指定模式打开一个文件,并返回file对象。该函数的语法格式为:
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/098-1.jpg?sign=1739301433-8j2nUk2e1r0xgfgNOWBsCYIoq4mfoTHY-0-c939b5270e3b8b42fe3cc2b5397287f3)
其中,各参数的含义如下。
• file:必需参数,指定文件路径和名称。
• mode:可选参数,指定文件打开模式,包括读、写、追加等各种模式。
• buffering:可选参数,设置缓冲(不影响结果)。
• encoding:可选参数,设置编码方式,一般使用UTF-8。
• errors:可选参数,指定当编码和解码错误时怎么处理,适用于文本模式。
• newline:可选参数,指定在文本模式下控制一行结束的字符。
• closefd:可选参数,指定传入的file参数类型。
• opener:可选参数,设置自定义文件打开方式,默认时为None。
注意:使用open函数打开文件操作完毕后,一定要保证关闭文件对象。关闭文件对象使用close函数。
使用open函数打开文件后会返回一个file对象,利用该对象的方法可以进行文件内容的读取、写入、截取和文件关闭等一系列操作,如表2-1所示。
表2-1 file对象的方法
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/099-1.jpg?sign=1739301433-KySlFKabWHp6nvELTWeTUOXoQkxT9N0k-0-3895b4550da13da07aa25fe24993c612)
2.1.2 创建文本文件并写入数据
当使用open函数打开文件时,如果指定mode参数的值为表2-2中的值,若文件不存在,则会创建新文件。
表2-2 写入文本文件时mode参数的设置
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/099-2.jpg?sign=1739301433-qEx6j0EEunS1hqMA5Ja4t5HTbcI5dPAH-0-64cffd7d84f2592d08b811800255fc7f)
例如,下面创建一个文本文件filetest.txt,放在D盘下。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/099-3.jpg?sign=1739301433-hmYbBcBdH6HTbyyfwB526cifwcWNm5sS-0-a139357438f3ef22177dd963cfc6e9f2)
open函数返回一个file对象,使用该对象的write方法向文件中写入数据。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/100-1.jpg?sign=1739301433-ejZfxFL4U5pWnuewDxj2YfqTN9xDRPEg-0-8b2f137f7b647aa573f2af94f5f71ba8)
返回值13表示文件中字节的长度。
现在打开D盘下的filetest.txt文件,会发现什么内容也没有。使用file对象的close方法关闭文件对象。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/100-2.jpg?sign=1739301433-rUMO7tPjjNeGZmt5TB6MjCJ3phFefNH9-0-64f12aa472c4c2cf679b15cca2aedffb)
现在打开该文件,发现刚刚写入的字符串"Hello Python!"显示出来了,如图2-1所示。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/100-01.jpg?sign=1739301433-NmRsfJLKC9xtzlnYS4fqrhccQuFnbfmH-0-aa61f38271fdc856789381f9b33111e2)
图2-1 创建文本文件并写入数据
使用open函数打开D盘下已经存在的filetest.txt文件,模式为“w”,然后使用file对象的write方法写入一个新的字符串,最后关闭文件对象。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/100-4.jpg?sign=1739301433-7MhYOuDYWQRkEyaPNveQXBFCxTp5wSjK-0-613c354767cab3cffa455c2df8804cfe)
打开文件,显示效果如图2-2所示。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/100-02.jpg?sign=1739301433-Ng9sRxOfBeCktyJiGm9W06qzXCNWMcTJ-0-09e50d586b2db45be5433e02120a87d9)
图2-2 打开文件重新写入数据
这说明在“w”模式下,当打开已经存在的文件并重新写入数据时,文件中原来的数据会被删除。
下面使用with语句打开文本文件后写入数据。使用这种方法的好处是执行完后会主动关闭文件,不需要使用file对象的close方法进行关闭。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/100-6.jpg?sign=1739301433-OeB7uHSG3fU68T1PIcHx5g18lqpYCawn-0-e327e392ec2ba97cc5071f49c5c7c32a)
打开文件,发现文件原来的内容被删除,重新写入了"Hello Python!"。
使用file对象的writelines方法,可以用列表结合换行符一次写入多行数据。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/101-1.jpg?sign=1739301433-YrU3JiqH37ml9PiqTUMSVU4Wxi806KQD-0-6d9bd9997b58941487e4a6aa07393294)
打开文件,发现列表中的两个元素数据已经分两行写入。
下面打开文本文件后使用循环连续写入数据。其中,“\r”表示回车,“\n”表示换行。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/101-2.jpg?sign=1739301433-Zp8wjiaeHatAWNO4L1V2gLvhzsRCIjYP-0-8c5b385e6da542df7eb4d5b18b79ee8c)
打开文件,发现已经连续写入了10行"Hello Python!"。
2.1.3 读取文本文件数据
当使用open函数打开文件时,如果指定mode参数的值为表2-3中的值,则读取文件的内容。
表2-3 读取文本文件时mode参数的设置
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/101-3.jpg?sign=1739301433-LhkHyrkLJyQbzxjaMJuoi60NVylSD8sS-0-d57ef2d1b0218aca3dbaa4a9db42c5a5)
2.1.2节最后使用一个for循环向D盘下的filetest.txt文件中写入了10行数据。下面使用open函数打开该文件,将mode参数的值设置为“r”,只读。然后使用file对象的read方法读取文件的内容。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/101-4.jpg?sign=1739301433-slOkc9gPHevvaVLpUHQCR9WLYLx4vjFp-0-c5e799edcf61388c8c4bf001fa6b7e6a)
下面使用file对象的write方法向文件中写入数据。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/101-5.jpg?sign=1739301433-8TfSNx7fZwlzX6eDIxPyd8GOXjSvN7HP-0-e5a5b506c556bd366c2969a185d94e00)
可见,因为打开文件时设置mode参数为“r”,只读,所以试图向文件中写入数据时报错。
下面使用file对象的readline方法逐行读取数据。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/101-6.jpg?sign=1739301433-NFBWKcWgDkmvWxe1h7ISZriy6Z1JlijR-0-5f3f178b482e10ae392f497fb30ef7ae)
读取第1行数据:
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/102-1.jpg?sign=1739301433-yNt2lpIoWkJhlyhON7335eMPdzki65Cc-0-d277ebe36b9dd80b42ecdc116556f483)
读取第2行数据,是一个空行:
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/102-2.jpg?sign=1739301433-l3oCDeVEnag7pGAUR5gcWOyq9jZ2l1BN-0-e956fb50f52284cba86304b8f2c2ffcb)
读取第3行数据的前5个字符:
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/102-3.jpg?sign=1739301433-NvWrGqjOGzEjFkRAgTJORokfS2Kw4Eut-0-29269a30826f71e381c1f7d966caf730)
下面使用file对象的readlines方法读取所有行数据。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/102-4.jpg?sign=1739301433-Kbl2IPXC1KAwZBC6juTNRcA8eZxEA2a4-0-6c51272a7e8202ac872bedece5cfdbaf)
2.1.4 向文本文件中追加数据
当使用open函数打开已经存在的文件时,如果指定mode参数的值为表2-4中的值,则可以在原有内容后面追加数据,即原来的数据保留,继续追加数据。
表2-4 向文本文件中追加数据时mode参数的设置
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/102-5.jpg?sign=1739301433-C1EUtr6nRV4oIKKbnCjjS6v54SpVhGlF-0-7c60c7396627a01eb0efe37cc939fc39)
下面打开D盘下的filetest.txt文件,设置mode参数的值为“a”。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/102-6.jpg?sign=1739301433-hG01UGo0wqkGK9PddjsjiswaYlg80Xk9-0-c49bbf97f7d8fdc88e4cb82fcc28c6d0)
添加新行:
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/102-7.jpg?sign=1739301433-axqlQ3s2VmgzZb2my2zIA8JBDWVCBlql-0-9ae2bfe7dd5e0ea588df71ae85772f9e)
打开该文本文件,可以看到在原有内容的后面添加了新行数据,原有内容仍然保留。
2.1.5 读/写二进制文件数据
本章前面各节介绍了使用Python的open函数实现文本文件数据读/写的方法,使用该函数还可以进行二进制文件数据的读/写。很多图形、图像和视频文件都采用二进制格式读/写数据。
在实现时只需要修改mode参数的值即可。表2-5中列出了读/写二进制文件时mode参数的设置,可见,这些参数与文本文件设置的基本相同,只是多了一个“b”。“b”是binary,即二进制的意思。
表2-5 读/写二进制文件时mode参数的设置
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/103-1.jpg?sign=1739301433-o7wohITpu47QZWqSCxd7wCyk0bdkMrkM-0-cd636cf8ce29078b11ae77e372dd5bbe)
二进制文件是以字节为单位存储的,所以使用file对象的write方法写入数据时,需要先将数据从字符串转换为字节流,使用bytes函数进行转换,指定编码方式。从二进制文件读取数据时,则需要使用decode方法对read方法读出的数据进行解码,同样要指定编码方式。
下面假设要保存一个直线段图形的数据,包括直线段的起点坐标(10,10)和终点坐标(100,200),保存为D盘下的二进制文件bftest.cad,cad为自定义的扩展名。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/103-2.jpg?sign=1739301433-4KdOTQkZbrjhHmaoS4gbCTqHLteQAMP7-0-fa3ac9ab12318604c6d0206784018357)
现在可以在D盘下找到刚刚创建的二进制文件bftest.cad。
在打开该文件时,需要能获取到先前保存的直线段起点和终点的坐标数据,以便重新绘图。此时使用open函数打开文件时,将mode参数的值设置为“rb”,以二进制格式读取。然后使用file对象的read方法读取数据,该数据不能直接用,还需要使用decode方法以先前保存时指定的编码方式解码得到字符串。最后使用split方法从该字符串中获取直线段起点和终点的坐标数据字符串,并使用int函数将其转换为整型数字。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/104-1.jpg?sign=1739301433-Ymn2LpPdE6BTsykKyZKnuq3G6FQQmotm-0-5e40fdd33766a1891b52c4675a56a849)
在得到坐标数据后,就可以使用绘图函数把直线段重新绘制出来了。这就是图形保存和打开的完整过程,实际上是图形控制点数据的保存和打开处理。
2.1.6 使用struct模块读取二进制文件
2.1.5节使用Python的open函数实现了二进制文件的读/写,在使用该方法保存不同类型的数据时需要先将它们转换为字符串,再按照一定的编码方式将字符串转换为字节流进行写入;当从文件中将数据读取出来时则反过来,需要先将读取出来的数据按同样的编码方式解码成字符串,然后从字符串中获取数据。这个过程相对比较烦琐,Python的struct模块对该过程进行了简化,可以比较方便地处理不同类型数据的读/写。
下面使用struct模块处理与2.1.5节相同的直线段数据的二进制文件写入和读取。在使用struct模块前,需要先用import命令导入它。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/104-2.jpg?sign=1739301433-PUSXJmiOyIgr26Baqpdo6pI7VA1hYLGH-0-6cb088c723514a956cb72ca467342c4f)
当使用file对象的write方法写入数据时,使用struct模块的pack函数将坐标数据转换为字符串,然后写入该字符串。该函数的语法格式为:
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/104-3.jpg?sign=1739301433-Pv7OHYbMWt0ZpSSpnGiy3px34W6CFZpa-0-fa7731bbb9e1b23a95e37bc56184e6d1)
其中,fmt参数指定数据类型,如整型数字用“i”表示,浮点型数字用“f”表示。按照先后次序,每个数据都要指定数据类型。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/104-4.jpg?sign=1739301433-CPu0bnNSUb2OlJ8xjVbvCLbD9StEwzVy-0-76dc4e85e9075f96a7a2350dd9ceee9f)
现在直线段的坐标数据被保存到D盘下的二进制文件bftest2.cad中了。
在读取数据时,需要使用struct模块的unpack函数进行解包,解包得到的数据以元组方式返回。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/104-5.jpg?sign=1739301433-vCl27vSCuor1eIvIj35mcsJDR8rmWfg1-0-837aa1212f2cb1fd73eadec9c5d6946e)
与2.1.5节对比,可见,使用struct模块读/写二进制文件比直接使用file对象的方法读/写要方便得多。