文件与文件路径
文件有两个关键属性:文件名
和路径
。
路径指明了文件在计算机上的位置。
文件名中,最后一个句点之后的部分称为文件的“扩展名”,它指出了文件的类型
目录也叫文件夹,文件夹可以包含文件和其他文件夹
路径分隔符
在 Windows 上,路径书写使用倒斜杠作为文件夹之间的分隔符
在 OS X 和Linux 上,使用正斜杠作为它们的路径分隔符
解决方法: 如果将单个文件和路径上的文件夹名称的字符串传递给它,os.path.join()就会返回一个文件路径的字符串,包含正确的路径分隔符。例如:os.path.join('usr', 'bin', 'spam')
当前工作目录
os.getcwd()
:取得当前工作路径的字符串
os.chdir()
:改变当前工作路径
绝对路径与相对路径
有两种方法指定一个文件路径:
- 绝对路径,总是从根文件夹开始
- 相对路径,它相对于程序的当前工作目录
用os.makedirs()创建新文件夹
os.makedirs()将创建所有必要的中间文件夹,目的是确保完整路径名存在
os.path模块
os.path 模块包含了许多与文件名和文件路径相关的有用函数
因为 os.path 是 os 模块中的模块,所以只要执行 import os 就可以导入它
处理绝对路径和相对路径
os.path 模块提供了一些函数,返回一个相对路径的绝对路径,以及检查给定的路径是否为绝对路径:
- 调用 os.path.abspath(path)将返回参数的绝对路径的字符串。这是将相对路径转换为绝对路径的简便方法。
- 调用 os.path.isabs(path),如果参数是一个绝对路径,就返回 True,如果参数是一个相对路径,就返回 False。
- 调用 os.path.relpath(path, start)将返回从 start 路径到 path 的相对路径的字符串。如果没有提供 start,就使用当前工作目录作为开始路径。
调用 os.path.dirname(path)将返回一个字符串,它包含 path 参数中最后一个斜杠之前的所有内容。调用 os.path.basename(path)将返回一个字符串,它包含 path 参数中最后一个斜杠之后的所有内容。
如果同时需要一个路径的目录名称和基本名称,就可以调用 os.path.split()
可以调用 os.path.dirname()和 os.path.basename(),将它们的返回值放在一个元组中,从而得到同样的元组
os.path.split()不会接受一个文件路径并返回每个文件夹的字符串的列表。如果需要这样,请使用split()字符串方法,并根据os.path.sep 中的字符串进行分割。回忆一下,根据程序运行的计算机,os.path.sep 变量设置为正确的文件夹分割斜杠。
split()字符串方法将返回一个列表,包含该路径的所有部分。如果向它传递os.path.sep,就能在所有操作系统上工作。
查看文件大小和文件夹内容
一旦有办法处理文件路径,就可以开始搜集特定文件和文件夹的信息。os.path 模块提供了一些函数,用于查看文件的字节数以及给定文件夹中的文件和子文件夹
- 调用 os.path.getsize(path)将返回 path 参数中文件的字节数
- 调用 os.listdir(path)将返回文件名字符串的列表,包含 path 参数中的每个文件(请注意,这个函数在 os 模块中,而不是 os.path)
检查路径有效性
如果你提供的路径不存在,许多 Python 函数就会崩溃并报错。os.path 模块提供了一些函数,用于检测给定的路径是否存在,以及它是文件还是文件夹
- 如果 path 参数所指的文件或文件夹存在,调用 os.path.exists(path)将返回 True,否则返回 False。
- 如果 path 参数存在,并且是一个文件,调用 os.path.isfile(path)将返回 True,否则返回 False。
- 如果 path 参数存在,并且是一个文件夹,调用 os.path.isdir(path)将返回 True,否则返回 False。
利用 os.path.exists()函数,可以确定 DVD 或闪存盘当前是否连在计算机上
文件读写过程
纯文本文件
只包含基本文本字符,不包含字体、大小和颜色信息
二进制文件
是所有其他文件类型,诸如字处理文档、PDF、图像、电子表格和可执行程序
用open()函数打开文件
要用 open()函数打开一个文件,就要向它传递一个字符串路径,表明希望打开的文件。这既可以是绝对路径,也可以是相对路径。open()函数返回一个 File 对象
读取文件内容
如果你希望将整个文件的内容读取为一个字符串值,就使用 File 对象的 read()方法
如果你将文件的内容看成是单个大字符串,read()方法就返回保存在该文件中的这个字符串
或者,可以使用 readlines()方法,从该文件取得一个字符串的列表。列表中的每个字符串就是文本中的每一行
每个字符串值都以一个换行字符
结束。除了文件的最后一行。与单个大字符串相比,字符串的列表通常更容易处理
写入文件
如果打开文件时用读模式,就不能写入文件
需要以“写入纯文本模式”或“添加纯文本模式”打开该文件,或简称为“写模式”和“添加模式”
写模式将覆写原有的文件,从头开始,就像你用一个新值覆写一个变量的值
将'w'作为第二个参数传递给 open(),以写模式打开该文件
将'a'作为第二个参数传递给 open(),以添加模式打开该文件
如果传递给 open()的文件名不存在,写模式和添加模式都会创建一个新的空文件。在读取或写入文件后,调用 close()方法,然后才能再次打开该文件。
write()方法不会像 print()函数那样,在字符串的末尾自动添加换行字符。必须自己添加该字符
用shelve模块保存变量
要利用shelve模块读写数据,首先要导入它。调用函数shelve.open()并传入一个文件名,然后将返回的值保存在一个变量中。
可以对这个变量的 shelf 值进行修改,就像它是一个字典一样。当你完成时,在这个值上调用close()。
这些二进制文件包含了存储在 shelf 中的数据。这些二进制文件的格式并不重要,你只需要知道 shelve 模块做了什么,而不必知道它是怎么做的。该模块让你不用操心如何将程序的数据保存到文件中。
你的程序稍后可以使用 shelve 模块,重新打开这些文件并取出数据。shelf 值不必用读模式或写模式打开,因为它们在打开后,既能读又能写。
就像字典一样,shelf 值有 keys()和 values()方法,返回 shelf 中键和值的类似列表的值。因为这些方法返回类似列表的值,而不是真正的列表,所以应该将它们传递给 list()函数,取得列表的形式
用pprint.pformat()函数保存变量
pprint.pprint()函数将列表或字典中的内容“漂亮打印”到屏幕,而 pprint.pformat()函数将返回同样的文本字符串,但不是打印它。这个字符串不仅是易于阅读的格式,同时也是语法上正确的 Python 代码。假定你有一个字典,保存在一个变量中,你希望保存这个变量和它的内容,以便将来使用。pprint.pformat()函数将提供一个字符串,你可以将它写入.py 文件。该文件将成为你自己的模块,如果你需要使用存储在其中的变量,就可以导入它。
import 语句导入的模块本身就是 Python 脚本。如果来自 pprint.pformat()的字符串保存为一个.py 文件,该文件就是一个可以导入的模块,像其他模块一样。
由于 Python 脚本本身也是带有.py 文件扩展名的文本文件,所以你的 Python 程序甚至可以生成其他 Python 程序。然后可以将这些文件导入到脚本中
创建一个.py 文件(而不是利用 shelve 模块保存变量)的好处在于,因为它是一个文本文件,所以任何人都可以用一个简单的文本编辑器读取和修改该文件的内容。但是,对于大多数应用,利用 shelve 模块来保存数据,是将变量保存到文件的最佳方式。只有基本数据类型,诸如整型、浮点型、字符串、列表和字典,可以作为简单文本写入一个文件。例如,File 对象就不能够编码为文本。
shutil模块
shutil(或称为 shell 工具)模块中包含一些函数,让你在 Python 程序中复制、移动、改名和删除文件。要使用 shutil 的函数,首先需要 import shutil。
复制文件和文件夹
shutil.copy(source, destination)
,将路径source 处的文件复制到路径destination处的文件夹(source 和 destination 都是字符串)。如果 destination 是一个文件名,它将作为被复制文件的新名字。该函数返回一个字符串,表示被复制文件的路径。
shutil.copy()
将复制一个文件,shutil.copytree()
将复制整个文件夹,以及它包含的文件夹和文件。调用 shutil.copytree(source, destination)
,将路径 source 处的文件夹,包括它的所有文件和子文件夹,复制到路径 destination 处的文件夹。source 和destination 参数都是字符串。该函数返回一个字符串,是新复制的文件夹的路径。
文件和文件夹的移动与改名
shutil.move(source, destination)
,将路径 source 处的文件夹移动到路径destination,并返回新位置的绝对路径的字符串。
如果 destination 指向一个文件夹,source 文件将移动到 destination 中,并保持原来的文件名。
destination 路径也可以指定一个文件名。在下面的例子中,source 文件被移动并改名。
构成目的地的文件夹必须已经存在,否则 Python 会抛出异常
永久删除文件和文件夹
利用 os 模块中的函数,可以删除一个文件或一个空文件夹。但利用 shutil 模块,可以删除一个文件夹及其所有的内容。
- 用 os.unlink(path)将删除 path 处的文件。
- 调用 os.rmdir(path)将删除 path 处的文件夹。该文件夹必须为空,其中没有任何文件和文件夹。
- 调用 shutil.rmtree(path)将删除 path 处的文件夹,它包含的所有文件和文件夹都会被删除。
用send2trash模块安全地删除
因为 Python 内建的 shutil.rmtree()函数不可恢复地删除文件和文件夹,所以 用起来可能有危险。删除文件和文件夹的更好方法,是使用第三方的 send2trash 模块。你可以在终端窗口中运行 pip install send2trash,安装该模块
利用 send2trash,比 Python 常规的删除函数要安全得多,因为它会将文件夹和文件发送到计算机的垃圾箱或回收站,而不是永久删除它们。如果因程序缺陷而用send2trash 删除了某些你不想删除的东西,稍后可以从垃圾箱恢复。
一般来说,总是应该使用 send2trash.send2trash()函数来删除文件和文件夹。虽然它将文件发送到垃圾箱,让你稍后能够恢复它们,但是这不像永久删除文件,不会释放磁盘空间。如果你希望程序释放磁盘空间,就要用 os 和 shutil 来删除文件和文件夹。请注意,send2trash()函数只能将文件送到垃圾箱,不能从中恢复文件。
遍历目录树
os.walk()函数被传入一个字符串值,即一个文件夹的路径。你可以在一个 for循环语句中使用 os.walk()函数,遍历目录树,就像使用 range()函数遍历一个范围的数字一样。
os.walk()在循环的每次迭代中,返回 3 个值:
- 当前文件夹名称的字符串。
- 当前文件夹中子文件夹的字符串的列表。
- 当前文件夹中文件的字符串的列表。
所谓当前文件夹,是指 for 循环当前迭代的文件夹。程序的当前工作目录,不会因为os.walk()而改变。
用zipfile模块压缩文件
读取ZIP文件
要读取ZIP文件的内容,首先必须创建一个ZipFile对象(请注意大写首字母 Z和 F)。ZipFile对象在概念上与File对象相似
要创建一个 ZipFile对象,就调用 zipfile.ZipFile()函数,向它传入一个字符串,表示.zip 文件的文件名。
请注意,zipfile 是 Python 模块的名称,ZipFile()是函数的名称。
ZipFile 对象有一个 namelist()方法,返回 ZIP 文件中包含的所有文件和文件夹的字符串的列表。这些字符串可以传递给 ZipFile 对象的 getinfo()方法,返回一个关于特定文件的 ZipInfo 对象。ZipInfo 对象有自己的属性,诸如表示字节数的 file_size和 compress_size,它们分别表示原来文件大小和压缩后文件大小。ZipFile 对象表示整个归档文件,而 ZipInfo 对象则保存该归档文件中每个文件的有用信息。
从ZIP文件中解压缩
ZipFile 对象的 extractall()方法从ZIP文件中解压缩所有文件和文件夹,放到当前工作目录中
可以向extractall()传递的一个文件夹名称,它将文件解压缩到那个文件夹,而不是当前工作目录
如果传递给 extractall()方法的文件夹不存在,它会被创建
ZipFile 对象的 extract()方法从 ZIP 文件中解压缩单个文件
传递给 extract()的字符串,必须匹配 namelist()返回的字符串列表中的一个。或者,你可以向 extract()传递第二个参数,将文件解压缩到指定的文件夹,而不是当前工作目录。如果第二个参数指定的文件夹不存在,Python 就会创建它。extract()的返回值是被压缩后文件的绝对路径。
创建和添加到ZIP文件
要创建你自己的压缩 ZIP 文件,必须以“写模式”打开 ZipFile 对象,即传入'w'作为第二个参数(这类似于向 open()函数传入'w',以写模式打开一个文本文件)。
如果向 ZipFile 对象的 write()方法传入一个路径,Python 就会压缩该路径所指的文件,将它加到 ZIP 文件中。write()方法的第一个参数是一个字符串,代表要添加的文件名。第二个参数是“压缩类型”参数,它告诉计算机使用怎样的算法来压缩文件。可以总是将这个值设置为 zipfile.ZIP_DEFLATED(这指定了 deflate 压缩算法,它对各种类型的数据都很有效)。
就像写入文件一样,写模式将擦除 ZIP 文件中所有原有的内容。如果只是希望将文件添加到原有的 ZIP 文件中,就要向 zipfile.ZipFile()传入'a'作为第二个参数,以添加模式打开 ZIP 文件。