第八章:读写文件

前言

本章解释程序如何读写文本文件的内容,并将信息保存到硬盘文件中。

程序运行时,变量是保存数据的好方法,但如果希望程序结束后数据仍然保持,此时需要将数据保存在文件中。文件有两个关键属性:“文件名”和路径。路径指明了文件在计算机中的位置。文件名中,最后一个句点后的内容是文件的“扩展名”,表明文件的类型。注意点:文件夹名称和文件名在Windows和OS X上是不区分大小写的,但在Linux上是区分大小写的。

在Windows上,路径书写使用倒斜杠作为文件夹之间的分隔符,而在OS X和Linux上,使用正斜杠作为它们的路径分隔符。所以想要程序运行在所有操作系统上,在编写Python脚本时需要考虑周全。

在os.path.join()函数中传入单个文件或路径上的文件夹名称的字符串,会返回一个文件路径的字符串,包含正确的路径分隔符。例子如下:

import os
print(os.path.join('usr','bin','spam'))
结果
usr\bin\spam

上述例子返回的是’usr\bin\spam’(而在上一个返回的有两个倒斜杠,有一个倒斜杠是转义字符),在OS X和Linux系统上就会是’usr/bin/spam’。

将一个文件名列表的名称添加倒文件夹名称的末尾,例子如下:

import os
myFiles = ['accounts.txt','details.csv','invite.docx']
for filename in myFiles:
    print(os.path.join('c:\\Users\\ww',filename))
结果
c:\Users\ww\accounts.txt
c:\Users\ww\details.csv
c:\Users\ww\invite.docx

每个运行在计算机中的程序,都有一个当前的工作目录,或者cwd。所有没有从根文件夹开始的文件名或路径,都可以假定在当前工作目录下。利用os.getcwd()函数,可以得到当前工作路径的字符串,并利用os.chdir()改变它。例子如下:

import os
print(os.getcwd())
os.chdir('C:\\Windows\\System32')
print(os.getcwd())
结果
E:\python1
C:\Windows\System32

注意:当前工作过目录是标准术语,没有当前工作文件夹这种说法。

有两种方法指定一个文件路径。绝对路径:总是从根文件夹开始。相对路径:它相对于程序的当前工作目录。程序可以用os.makedirs()函数创建新文件夹(目录)。例子如下:

import os
os.makedirs('E:\\delicious\\ww')
os.makedirs('.\\delicious\\ww')
os.makedirs('..\\aa\\ww')

 

 

 有关os.path模块的一些函数介绍。调用os.path.abspath(path)将返回参数的绝对路径的字符串。这是将相对路径转换为绝对路径的简便方法。调用os.path.isabs(path),如果参数是绝对路径,返回True。调用os.path.relpath(path,start)返回从start路径到path的相对路径的字符串,如果没有提供start,就使用当前工作目录作为开始路径。

import os
print(os.path.abspath('.'))
print(os.path.abspath('.\\venv'))
print(os.path.isabs(os.path.abspath('.')))
print(os.path.relpath(os.path.abspath('.')))
print(os.path.relpath(os.path.abspath('.'),'E:\\'))
print(os.path.isabs('.'))
print(os.path.relpath('E:\\python1\\venv','E:\\DSP\\import'))
结果
E:\python1
E:\python1\venv
True
.
python1
False
..\..\python1\venv

注意:有关路径的代码需要根据自己计算机上存在的文件夹完成,无法直接复制实现。

调用os.path.dirname(path)返回一个字符串,包含path参数中最后一个斜杠之前的所有内容,也就是目录名称。调用os.path.basename(path)将返回一个字符串,它包含path参数中最后一个斜杠之后的所有内容,也就是基本名称。例子如下:

import os
print(os.path.basename('E:\\python1'))
print(os.path.dirname('E:\\python1'))
结果
python1
E:\

如果需要同时胡哦的目录名称和基本名称,调用os.path.split(),得到这两个字符串的元组,例子如下:

import os
print(os.path.split('E:\\python1'))
结果
('E:\\', 'python1')
当然也可以将os.path.dirname()和os.path.basename()的返回值放到元组中,效果类似。
import os
print((os.path.dirname('E:\\python1'),os.path.basename('E:\\python1')))
结果
('E:\\', 'python1')

注意,os.path.split()不会接受一个文件路径并返回每个文件夹字符串的列表。如果需要胡哦的,使用split()字符串的方法,并根据os.path.sep中的字符串进行分隔。例子如下:

import os
print('E:\\python1\\venv'.split(os.path.sep))
结果
['E:', 'python1', 'venv']

os.path模块提供了一些函数,用于查看文件的字节数和给定文件夹的文件和子文件夹。

调用os.path.getsize(path)将返回path参数中文件的字节数。

调用os.listdir(path)将返回文件名字符串的列表,包含path参数中的每个文件。

import os
print(os.path.getsize('E:\\python1\\718.py'))
print(os.listdir('E:\python1'))
结果
1024
['.idea', '718.py', '719.py', '721.py', '724.py', '725.py', '726.py', '727.py', 'main.py', 'pyperclip', 'venv']

注意这里的路径也是根据自己的计算机而定的。如果想知道这个目录下所有文件的总字节数,例子如下:

import os
totalSize = 0
for filename in os.listdir('E:\python1'):
    totalSize = totalSize +os.path.getsize(os.path.join('E:\python1',filename))
print(totalSize)
结果
21146

os.path模块提供了一些函数,用于检测给定的路径是否存在,以及它是文件还是文件夹。

调用os.path.exists(path),如果path参数所指的文件或文件夹存在,则返回True。

调用os.path.isfile(path),如果path参数存在并且是一个文件,则返回True。

调用os.path.isdir(path),如果path参数存在并且是一个文件夹,则返回True。

import os
print(os.path.exists('E:\python1'))
print(os.path.isdir('E:\python1\\venv'))
print(os.path.isfile('E:\python1\\718.py'))
print(os.path.exists('E:\\dqwfq'))
print(os.path.isdir('E:\python1\\718.py'))
print(os.path.isfile('E:\python1\\venv'))
结果
True
True
True
False
False
False

当熟悉了处理文件夹和相对路径后,就可以指定文件的位置,进行读写。下面介绍的函数适用于纯文本文件。“纯文本文件”只包含基本文本字符,不包含字体,大小和颜色信息。比如带有.txt扩展名和.py扩展名的文件都是纯文本文件。它们可以被Windows的Notepad或OS X的TextEdit应用打开。程序可以轻易读取文本文件的内容,将它们作为普通的字符串值。

“二进制文件”是所有其他文件类型,比如字处理文档,PDF,图像,电子表格和可执行程序。如果用NotePad或TextEdit打开一个二进制文件,就会出现乱码。不同的二进制文件需要时使用不同的处理方式,shelve模块也能处理二进制模块,后续可能讲到。

一般在Python中,读写文件有三个步骤:(1)调用open()函数,返回一个File对象;(2)调用File对象的read()或write()方法;(3)调用File对象的close()方法,关闭该文件。这里跟C++读取文件很类似。例如创建一个文件文本,名为hello.txt,内容是Hello World!,例子如下:

import os
helloFile = open('.\hello.txt')
helloFile1 = open('.\hello.txt','r') #与上面等同
helloContent =helloFile.read()
helloContent1 = helloFile1.read()
print(helloContent)
print(helloContent1)
结果
Hello World!
Hello World!

也可以使用readlines()方法,从该文件中取得字符串的列表。例表中的每个字符串是文本中的一行,例如创建一个sonnet29.txt,写入下列文本:

When ,in disgrace with fortune,
I all alone,
And trouble,
And look upon myself.
例子如下:
import os
sonnetFile = open('sonnet29.txt')
print(sonnetFile.readlines())
结果
['When ,in disgrace with fortune,\n', 'I all alone,\n', 'And trouble,\n', 'And look upon myself.\n']

如果打开文件时用读模式,就不能写入文件。你需要以“写入纯文本模式”或“添加纯文本模式”打开该文件,简称“写模式”和“添加模式”。写模式将覆盖原来有的文件,open()的第二个参数是’w’就是写模式。添加模式是在已有文件的末尾添加文本。open()的第二个参数是’a’,就是添加模式。如果传递给open()的文件名不存在,写模式和添加模式都会创建一个新的空文件,在读取或写入文件后,调用close()方法,然后才能再次打开该文件。例子如下:

import os
baconFile = open('bacon.txt','w')
baconFile.write('Hello World!\n')
baconFile.close()
baconFile = open('bacon.txt','a')
baconFile.write('Bacon is not a vegetable.')
baconFile.close()
baconFile =open('bacon.txt')
content = baconFile.read()
baconFile.close()
print(content)
结果
Hello World!
Bacon is not a vegetable.

上面代码实现的功能是创建一个bacon.txt文件并写入上述字符串。注意:write()方法不会像print()函数那样,在字符串的末尾自动添加换行符,需要手动添加。

利用shelve模块,可以将Python程序中的变量保存到二进制的shelf文件中。这样程序就可以从硬盘中恢复变量的数据。shelve模块可以在程序中添加“保存”和“打开”功能。例如,如果运行一个程序,并输入一些配置设置,可以将这些设置保存到一个shelf文件,然后让程序在下一次运行时加载它们。例子如下:

import shelve
shelfFile = shelve.open('mydata')
cats = ['Zophie','Pooka']
shelfFile['cats'] = cats
shelfFile.close()

在Windows上运行上面的代码,会在当前的工作目录下有三个新文件:mydata.bak,mydata.dat和mydata.dir。如果在OS X上,只会创建一个mydata.db文件。我们不需要关心这些文件的格式,只需要知道二进制文件包含了存储在shelf中的数据,再次使用shelve模块会重新打开文件并取出数据。shelf值不需要用读模式或写模式打开,因为它们打开后既能读又能写,例子如下:

import shelve
shelfFile = shelve.open('mydata')
print(shelfFile)
print(shelfFile['cats'])
shelfFile.close()
结果
<shelve.DbfilenameShelf object at 0x00000271E5021828>
['Zophie', 'Pooka']

我们打开了shelf文件,检查我们的数据是否存储成功,从结果来看,返回的是我们存储的列表,最后记得close()。跟字典类似,shelf值有keys()和values()方法,返回shelf中键和值的类似列表的值。但这些方法返回类似列表的值,而不是真正的列表,应该将它们传递给list()函数,取得列表的形式。例子如下:

import shelve
shelfFile = shelve.open('mydata')
print(list(shelfFile.keys()))
print(list(shelfFile.values()))
print(shelfFile.keys())
print(shelfFile.values())
shelfFile.close()
结果
['cats']
[['Zophie', 'Pooka']]
KeysView(<shelve.DbfilenameShelf object at 0x00000208BBCE15F8>)
ValuesView(<shelve.DbfilenameShelf object at 0x00000208BBCE15F8>)

创建文件时,如果需要在Notepad或TextEdit这样的文本编辑器中读取它们,纯文本就非常有用。但是如果想要保存Python程序中的数据,就需使用shelve模块。

第五章介绍的pprint.pprint()函数将列表或字典中的内容“漂亮打印”到屏幕,而pprint.pformat()函数将返回同样的文本字符串,但不是打印它。这个字符串不仅是易于阅读的格式,同时在语法上也是正确的。假如你有一个字典,保存在一个变量中,你希望保存这个变量和它的内容,方便以后调用。Pprint.pformat()函数将提供一个字符串,将它写入.py文件,该文件就成为自己定义的模块,如果想要使用存储其中的变量,就可以导入它。例子如下:

import pprint
cats = [{'name':'Zop','desc':'chub'},{'name':'Poo','desc':'flu'}]
print(pprint.pformat(cats))
fileObj = open('myCat.py','w')
fileObj.write('cats = '+pprint.pformat(cats)+'\n')
fileObj.close()
结果
[{'desc': 'chub', 'name': 'Zop'}, {'desc': 'flu', 'name': 'Poo'}]

上述程序创建了一个myCat.py文件并写入字符串。import语句导入的模块本身就是Python脚本。如果来自pprint.pformat()的字符串保存为一个.py文件,该文件就是一个可以导入的模块。例子如下:

import myCat
print(myCat.cats)
print(myCat.cats[0])
print(myCat.cats[0]['name'])
结果
[{'desc': 'chub', 'name': 'Zop'}, {'desc': 'flu', 'name': 'Poo'}]
{'desc': 'chub', 'name': 'Zop'}
Zop

创建一个.py文件(而不是利用shelve模块保存变量)的好处在于,它是一个文本文件,是可以被任何人用简单的文本编辑器读取和修改的。但是,对于大部分应用,利用shelve模块来保存数据,是将变量保存文件的最佳方式。只有基本数据类型,比如整型、浮点型、字符串、列表和字典,可以作为简单文本写入一个文件。例如File对象就不能编码为文本。


总结

下一章将学习如何处理文件本身,包括复制,删除,重命名和移动等。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值