shutil(或称为 shell 工具)模块中包含一些函数,让你在 Python 程序中复制、移动、改名和删除文件。要使用 shutil 的函数,首先需要 import shutil。
复制文件和文件夹
shutil 模块提供了一些函数,用于复制文件和整个文件夹。调用shutil.copy(source, destination),将路径source 处的文件复制到路径destination处的文件夹(source 和 destination 都是字符串)。如果 destination 是一个文件名,它将作为被复制文件的新名字。该函数返回一个字符串,表示被复制文件的路径。在交互式环境中输入以下代码,看看 shutil.copy()的效果:
>>> import shutil, os
>>> os.chdir('C:\\')
>>> shutil.copy('C:\\spam.txt', 'C:\\delicious')
'C:\\delicious\\spam.txt'
>>> shutil.copy('eggs.txt', 'C:\\delicious\\eggs2.txt')
'C:\\delicious\\eggs2.txt'
第一个 shutil.copy()调用将文件 C:\spam.txt 复制到文件夹 C:\delicious。返回值是刚刚被复制的文件的路径。请注意,因为指定了一个文件夹作为目的地,原来的文件名 spam.txt 就被用作新复制的文件名。第二个 shutil.copy()调用也将文件C:\eggs.txt 复制到文件夹 C:\delicious,但为新文件提供了一个名字 eggs2.txt。shutil.copy()将复制一个文件,shutil.copytree()将复制整个文件夹,以及它包含的文件夹和文件。调用 shutil.copytree(source, destination),将路径 source 处的文件夹,包括它的所有文件和子文件夹,复制到路径 destination 处的文件夹。source 和destination 参数都是字符串。该函数返回一个字符串,是新复制的文件夹的路径。在交互式环境中输入以下代码:
>>> import shutil, os
>>> os.chdir('C:\\')
>>> shutil.copytree('C:\\bacon', 'C:\\bacon_backup')
'C:\\bacon_backup'
shutil.copytree()调用创建了一个新文件夹,名为 bacon_backup,其中的内容与原来的 bacon 文件夹一样。现在你已经备份了非常非常宝贵的“bacon”。
文件和文件夹的移动与改名
调用 shutil.move(source, destination),将路径 source 处的文件夹移动到路径destination,并返回新位置的绝对路径的字符串。如果 destination 指向一个文件夹,source 文件将移动到 destination 中,并保持原来的文件名。例如,在交互式环境中输入以下代码:
>>> import shutil
>>> shutil.move('C:\\bacon.txt', 'C:\\eggs')
'C:\\eggs\\bacon.txt'
假定在 C:\目录中已存在一个名为 eggs 的文件夹,这个 shutil.move()调用就是说,“将 C:\bacon.txt 移动到文件夹 C:\eggs 中。
如果在 C:\eggs 中原来已经存在一个文件 bacon.txt,它就会被覆写。因为用这种方式很容易不小心覆写文件,所以在使用 move()时应该注意。destination 路径也可以指定一个文件名。在下面的例子中,source 文件被移动并改名。
>>> shutil.move('C:\\bacon.txt', 'C:\\eggs\\new_bacon.txt')
'C:\\eggs\\new_bacon.txt'
这一行是说,“将 C:\bacon.txt 移动到文件夹 C:\eggs,完成之后,将 bacon.txt文件改名为 new_bacon.txt。”前面两个例子都假设在 C:\目录下有一个文件夹 eggs。但是如果没有 eggs 文件夹,move()就会将 bacon.txt 改名,变成名为 eggs 的文件。
>>> shutil.move('C:\\bacon.txt', 'C:\\eggs')
'C:\\eggs
这里,move()在 C:\目录下找不到名为 eggs 的文件夹,所以假定 destination 指的是一个文件,而非文件夹。所以 bacon.txt 文本文件被改名为 eggs(没有.txt 文件扩展名的文本文件),但这可能不是你所希望的!这可能是程序中很难发现的缺陷,因为 move()调用会很开心地做一些事情,但和你所期望的完全不同。这也是在使用move()时要小心的另一个理由。最后,构成目的地的文件夹必须已经存在,否则 Python 会抛出异常。在交互式环境中输入以下代码:
>>> shutil.move('spam.txt', 'c:\\does_not_exist\\eggs\\ham')
Traceback (most recent call last):
File "C:\Python34\lib\shutil.py", line 521, in move
os.rename(src, real_dst)
FileNotFoundError: [WinError 3] The system cannot find the path specified:
'spam.txt' -> 'c:\\does_not_exist\\eggs\\ham'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<pyshell#29>", line 1, in <module>
shutil.move('spam.txt', 'c:\\does_not_exist\\eggs\\ham')
File "C:\Python34\lib\shutil.py", line 533, in move
copy2(src, real_dst)
File "C:\Python34\lib\shutil.py", line 244, in copy2
copyfile(src, dst, follow_symlinks=follow_symlinks)
File "C:\Python34\lib\shutil.py", line 108, in copyfile
with open(dst, 'wb') as fdst:
FileNotFoundError: [Errno 2] No such file or directory: 'c:\\does_not_exist\\
eggs\\ham'
Python 在 does_not_exist 目录中寻找 eggs 和 ham。它没有找到不存在的目录,所以不能将 spam.txt 移动到指定的路径。
永久删除文件和文件夹
利用 os 模块中的函数,可以删除一个文件或一个空文件夹。但利用 shutil 模块,可以删除一个文件夹及其所有的内容。
• 用 os.unlink(path)将删除 path 处的文件。
• 调用 os.rmdir(path)将删除 path 处的文件夹。该文件夹必须为空,其中没有任何文件和文件夹。
• 调用 shutil.rmtree(path)将删除 path 处的文件夹,它包含的所有文件和文件夹都会被删除。
在程序中使用这些函数时要小心!可以第一次运行程序时,注释掉这些调用,并且加上 print()调用,显示会被删除的文件。这样做是一个好主意。下面有一个Python 程序,本来打算删除具有.txt 扩展名的文件,但有一处录入错误(用粗体突出显示 ),结果导致它删除了.rxt 文件。
import os
for filename in os.listdir():
if filename.endswith('.rxt'):
os.unlink(filename)
如果你有某些重要的文件以.rxt 结尾,它们就会被不小心永久地删除。作为替代,你应该先运行像这样的程序:
import os
for filename in os.listdir():
if filename.endswith('.rxt'):
#os.unlink(filename)
print(filename)
现在 os.unlink()调用被注释掉,所以 Python 会忽略它。作为替代,你会打印出将被删除的文件名。先运行这个版本的程序,你就会知道,你不小心告诉程序要删除.rxt 文件,而不是.txt 文件。在确定程序按照你的意图工作后,删除 print(filename)代码行,取消os.unlink(filename)代码行的注释。然后再次运行该程序,实际删除这些文件。
用 send2trash 模块安全地删除
因为 Python 内建的 shutil.rmtree()函数不可恢复地删除文件和文件夹,所以 用起来可能有危险。删除文件和文件夹的更好方法,是使用第三方的 send2trash 模块。你可以在终端窗口中运行 pip install send2trash,安装该模块(参见附录 A,其中更详细地解释了如何安装第三方模块)。利用 send2trash,比 Python 常规的删除函数要安全得多,因为它会将文件夹和文件发送到计算机的垃圾箱或回收站,而不是永久删除它们。如果因程序缺陷而用send2trash 删除了某些你不想删除的东西,稍后可以从垃圾箱恢复。安装 send2trash 后,在交互式环境中输入以下代码:
>>> import send2trash
>>> baconFile = open('bacon.txt', 'a') # creates the file
>>> baconFile.write('Bacon is not a vegetable.')
25
>>> baconFile.close()
>>> send2trash.send2trash('bacon.txt')
一般来说,总是应该使用 send2trash.send2trash()函数来删除文件和文件夹。虽然它将文件发送到垃圾箱,让你稍后能够恢复它们,但是这不像永久删除文件,不会释放磁盘空间。如果你希望程序释放磁盘空间,就要用 os 和 shutil 来删除文件和文件夹。请注意,send2trash()函数只能将文件送到垃圾箱,不能从中恢复文件。