![代替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=1739421364-8nJNWEA8sV6lEXq1n3zPUGFwCLpDzp3J-0-f8192b507dd1a8eff1ecd414e036504f)
其中,各参数的含义如下。
• 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=1739421364-80NhnR1pgRo7k7GeXsHj4ClZS8YkOxio-0-c54eb19103976a8d115057446a5ecfd1)
2.1.2 创建文本文件并写入数据
当使用open函数打开文件时,如果指定mode参数的值为表2-2中的值,若文件不存在,则会创建新文件。
表2-2 写入文本文件时mode参数的设置
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/099-2.jpg?sign=1739421364-wcI8pnaGZUrGmJcucWJ4DZvzc45po6ns-0-22050eb4f958672f0a93ecc59a07780e)
例如,下面创建一个文本文件filetest.txt,放在D盘下。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/099-3.jpg?sign=1739421364-GkTgObeuJlsPF2pU73oEWutpiZgvlFqh-0-1478d56d5d5cbc346344da658eff9cf2)
open函数返回一个file对象,使用该对象的write方法向文件中写入数据。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/100-1.jpg?sign=1739421364-ETTzy9ZkF2xWTKAEOO4Y50RwUfIQFoQ7-0-96f1e973c55cff51bd69a78eda193715)
返回值13表示文件中字节的长度。
现在打开D盘下的filetest.txt文件,会发现什么内容也没有。使用file对象的close方法关闭文件对象。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/100-2.jpg?sign=1739421364-EZu4l6zXNUSIhs6ghn2dFlnBrAEW2SSw-0-1abeefa3183631bb97b6f050509ce07a)
现在打开该文件,发现刚刚写入的字符串"Hello Python!"显示出来了,如图2-1所示。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/100-01.jpg?sign=1739421364-Sq48FeGJLGlMBf3avGcUNDOLYOEHSiBP-0-0dee4d9b665aa904fba819c03eaf4c11)
图2-1 创建文本文件并写入数据
使用open函数打开D盘下已经存在的filetest.txt文件,模式为“w”,然后使用file对象的write方法写入一个新的字符串,最后关闭文件对象。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/100-4.jpg?sign=1739421364-3KMxZx6WAYezrHnIPdqEV6njmzdKOcYm-0-46b4686527dc06f73e6fdc46dbfec51e)
打开文件,显示效果如图2-2所示。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/100-02.jpg?sign=1739421364-iDHviWv4D2cIcIUovcbNQlzOWuEH6QmN-0-6ce3f8e87e3266de23c65c47a3ecf870)
图2-2 打开文件重新写入数据
这说明在“w”模式下,当打开已经存在的文件并重新写入数据时,文件中原来的数据会被删除。
下面使用with语句打开文本文件后写入数据。使用这种方法的好处是执行完后会主动关闭文件,不需要使用file对象的close方法进行关闭。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/100-6.jpg?sign=1739421364-V0EZetehcxfNgPTGFzSzO1EsY23Yb2ha-0-132ac58af8360bfc21311194066581c9)
打开文件,发现文件原来的内容被删除,重新写入了"Hello Python!"。
使用file对象的writelines方法,可以用列表结合换行符一次写入多行数据。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/101-1.jpg?sign=1739421364-ObCIyvAV1q7v0phTX6GsEna7xBs0AqqV-0-485ad1bf02cdbe20a3fb72ad092522cb)
打开文件,发现列表中的两个元素数据已经分两行写入。
下面打开文本文件后使用循环连续写入数据。其中,“\r”表示回车,“\n”表示换行。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/101-2.jpg?sign=1739421364-AhC1qK02rcfamKh5W5bwuPfWMhh3B5NI-0-d9dea0b0a55177b0a911239d889ebeff)
打开文件,发现已经连续写入了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=1739421364-rSNrbL1H5t4hgE6l40fNfkWMU3jzwPUK-0-6a3397bf776e274f58fd54f9e8fb9827)
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=1739421364-WaxgZQoZwY4htQ4tNGox2PApKrOKnIWv-0-ccd515018d142e68d74b8905deb078d0)
下面使用file对象的write方法向文件中写入数据。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/101-5.jpg?sign=1739421364-x30VbCgwfA9FmXskKKOXCkrH23jqDJKU-0-e46c4ad7453337fb47be9729757da7f6)
可见,因为打开文件时设置mode参数为“r”,只读,所以试图向文件中写入数据时报错。
下面使用file对象的readline方法逐行读取数据。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/101-6.jpg?sign=1739421364-y4SDwV4f7iBIAQH1RPXG9237qWVN0uwL-0-2187630063b1a05f01e18eafaee21ec2)
读取第1行数据:
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/102-1.jpg?sign=1739421364-77YDyzQXhC4PPB84SEcwnNe71Xl3dhqH-0-84671e29da096618fd149ce0652e23d3)
读取第2行数据,是一个空行:
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/102-2.jpg?sign=1739421364-kPhimwrySd7YfbbGepvSyfOOtBtA6n0p-0-4aeb2f366ed25a771a15d8517d5c055d)
读取第3行数据的前5个字符:
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/102-3.jpg?sign=1739421364-z7SdY67Ew7pWjcTgJC8mt54hUfEIdJG0-0-5fc8bc724c7b1904c11e7ba6dd433567)
下面使用file对象的readlines方法读取所有行数据。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/102-4.jpg?sign=1739421364-7JBTPwuQQGA7o8GYxKUCUYajslGdB4hr-0-fd2809bb4b23b258983d1e5b3d4b9aca)
2.1.4 向文本文件中追加数据
当使用open函数打开已经存在的文件时,如果指定mode参数的值为表2-4中的值,则可以在原有内容后面追加数据,即原来的数据保留,继续追加数据。
表2-4 向文本文件中追加数据时mode参数的设置
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/102-5.jpg?sign=1739421364-pEfj9yeFVYfXPpDaVvDgLy42wUYFYXiU-0-41164fdd4c91ebb93979fe12bc07ca4a)
下面打开D盘下的filetest.txt文件,设置mode参数的值为“a”。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/102-6.jpg?sign=1739421364-1Yiqx203jFHSZtddNN7xroRiOTYBf4T6-0-7cd5a7b79bb6873168c7ca9b59ab98c3)
添加新行:
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/102-7.jpg?sign=1739421364-6s4XRdVKCVf55ssDpP6p4eRKCUL2urcb-0-81d34d8ded20750c17490bd4673e3773)
打开该文本文件,可以看到在原有内容的后面添加了新行数据,原有内容仍然保留。
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=1739421364-XNekISNvLVE5nl5TtyOcbduM1roxJ3HZ-0-f82bb2b84562fe961ef431c79fb12e86)
二进制文件是以字节为单位存储的,所以使用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=1739421364-Ab2Uk3bT7xeUuxqciE5tFHTIbPMnAIpv-0-b9f5d4f0eb4c5abddbe96b7c35a758da)
现在可以在D盘下找到刚刚创建的二进制文件bftest.cad。
在打开该文件时,需要能获取到先前保存的直线段起点和终点的坐标数据,以便重新绘图。此时使用open函数打开文件时,将mode参数的值设置为“rb”,以二进制格式读取。然后使用file对象的read方法读取数据,该数据不能直接用,还需要使用decode方法以先前保存时指定的编码方式解码得到字符串。最后使用split方法从该字符串中获取直线段起点和终点的坐标数据字符串,并使用int函数将其转换为整型数字。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/104-1.jpg?sign=1739421364-LO2opReut2VBTppmXygiBtpt9I8nYMlS-0-aeb39c2555b915569b8975d509a6055c)
在得到坐标数据后,就可以使用绘图函数把直线段重新绘制出来了。这就是图形保存和打开的完整过程,实际上是图形控制点数据的保存和打开处理。
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=1739421364-eXIMD3OPzb9XDXRU6NWd1Raa2KHIg9Fj-0-54c08520c778c340c3b2255f4ab3821b)
当使用file对象的write方法写入数据时,使用struct模块的pack函数将坐标数据转换为字符串,然后写入该字符串。该函数的语法格式为:
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/104-3.jpg?sign=1739421364-j0evgwRvDhD8pRtQR2kecTU1VDWG7uty-0-098db0033defa25a61d29bdd145ce3f7)
其中,fmt参数指定数据类型,如整型数字用“i”表示,浮点型数字用“f”表示。按照先后次序,每个数据都要指定数据类型。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/104-4.jpg?sign=1739421364-krWWEoQEC211WLhn35QCIyD4fFWkwzqr-0-0678d46277932a75f70d5b121fc87c56)
现在直线段的坐标数据被保存到D盘下的二进制文件bftest2.cad中了。
在读取数据时,需要使用struct模块的unpack函数进行解包,解包得到的数据以元组方式返回。
![](https://epubservercos.yuewen.com/10B311/23020647701664206/epubprivate/OEBPS/Images/104-5.jpg?sign=1739421364-aQ5sPqE2I61vQEKDlUeEWODnImN3FrlY-0-3ab49bad2c64929020508c220b02645d)
与2.1.5节对比,可见,使用struct模块读/写二进制文件比直接使用file对象的方法读/写要方便得多。