shutil
(或称为 shell
工具)模块中包含一些函数,在Python程序中复制、移动、改名和删除文件。
要使用 shutil
的函数,首先需要 import shutil
。
复制文件和文件夹
shutil
模块提供了一些函数,用于复制文件和整个文件夹。
调用 shutil.copy(source,destination)
,
将路径 source
处的文件复制到路径 destination
处的文件夹( source
和 destination
都是字符串)。
如果 destination
是一个文件名,它将作为被复制文件的新名字。
该函数返回一个字符串,表示被复制文件的路径。
在交互式环境中输入以下代码,看看 shutil.copy()
的效果:
import shutil, os
shutil.copy('./xx_chapter.ipynb','/tmp')
'/tmp/xx_chapter.ipynb'
shutil.copy('./xx_chapter.ipynb','/tmp/xx_new_chapter.ipynb')
'/tmp/xx_new_chapter.ipynb'
第一个 shutil.copy()
调用将文件 复制到文件夹
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
参数都是字符串。该函数返回一个字符串,是新复制的文件夹的路径。
在交互式环境中输入以下代码:
if os.path.exists('/tmp/dest_backup')==False:
shutil.copytree('./', '/tmp/dest_backup')
dest_dir = '/tmp/xx_dst'
if os.path.exists(dest_dir):
pass
else:
os.mkdir(dest_dir)
shutil.move('/tmp/xx_new_chapter.ipynb', '/tmp/xx_dst')
'/tmp/xx_dst/xx_new_chapter.ipynb'
假定在 /tmp
目录中已存在一个名为 dst
的文件夹,
这个 shutil.move()
调用就是说,将目标文件移动到文件夹 /tmp/dst
中。
如果在 /tmp/dst
中原来已经存在一个文件 new_chapter.ipynb
,它就会被覆写。
因为用这种方式很容易不小心覆写文件,所以在使用 move()
时应该注意。
destination
路径也可以指定一个文件名。
在下面的例子中,source
文件被移动并改名。
shutil.move('/tmp/xx_dst/xx_new_chapter.ipynb','/tmp/xx_dst/xx_new_chapter_2.ipynb')
'/tmp/xx_dst/xx_new_chapter_2.ipynb'
这一行是说,“将C:\bacon.txt移动到文件夹C:\eggs,
完成之后,将 bacon.txt
文件改名为 new_bacon.txt
。”
前面两个例子都假设在C:\目录下有一个文件夹eggs。
但是如果没有 eggs
文件夹, move()
就会将
bacon.txt
改名,变成名为 eggs
的文件。
from pathlib import Path
my_fies = Path("chd3_test/hello.txt")
if my_fies.is_file():
shutil.move('/home/shaopp/jubook/chd3_test/hello.txt', '/home/shaopp/jubook/chd3_test/eggs')
这里, move()
在C:\目录下找不到名为eggs的文件夹,
所以假定destination指的是一个文件,而非文件夹。
所以 bacon.txt
文本文件被改名为 eggs
(没有.txt 文件扩展名的文本文件),
这可能是程序中很难发现的缺陷,
因为 move()
调用会很开心地做一些事情,
但和所期望的完全不同。这也是在使用
move()
时要小心的另一个理由。
最后,构成目的地的文件夹必须己经存在, 否则 Python 会抛出异常。
永久删除文件和文件夹
利用 os
模块中的函数,
可以删除一个文件或一个空文件夹。
但利用 shutil
模块,
可以删除一个文件夹及其所有的内容。
- 用
os.unlink(path)
将删除path
处的文件。 - 调用
os.rmdir(path)
将删除path
处的文件夹。该文件夹必须为空,其中没有任何文件和文件夹。 - 调用
shutil.rmtree(path)
将删除path
处的文件夹,
它包含的所有文件和文件夹都会被删除。
在程序中使用这些函数时要小心!可以第一次运行程序时,
注释掉这些调用,并且加上 print()
调用,
显示会被删除的文件。这样做是一个好主意。
下面有一个Python程序,本来打算删除具有
.txt
扩展名的文件,但有一处录入错误(用粗体突出显示),
结果导致它删除了 .rxt
文件。
import os
os.chdir('/home/shaopp/jubook/chd3_test')
for filename in os.listdir():
if filename.endswith('.txt'):
os.unlink(filename)
如果有某些重要的文件以 .rxt
结尾,它们就会被不小心永久地删除。
作为替代,应该先运行像这样的程序:
import os
for filename in os.listdir('/home/shaopp/jubook/chd3_test'):
if filename.endswith('.txt'):
#os.unlink(filename)
print(filename)
现在 os.unlink()
调用被注释掉,所以Python会忽略它。
作为替代,会打印出将被删除的文件名。
先运行这个版本的程序,就会知道,不小心告诉程序要删除 .rxt
文件,
而不是 .txt
文件。
在确定程序按照自己的意图工作后,删除 print(filename)
代码行,
取消 os.imlink(filename)
代码行的注释。然后再次运行该程序,实际删除这些文件。
send2trash
模块安全删除
因为Python内建的 shutil.rmtree()
函数
不可恢复地删除文件和文件夹,所以用起来可能有危险。
删除文件和文件夹的更好方法,
是使用第三方的 send2trash
模块。
可以在终端窗口中运行如下命令安装该模块。
sudo apt install -y python3-send2trash
或
pip install send2trash
Requirement already satisfied: send2trash in /opt/conda/lib/python3.12/site-packages (1.8.3) Note: you may need to restart the kernel to use updated packages.
利用 send2trash
,比Python常规的删除函数要安全得多,
因为它会将文件夹和文件发送到计算机的垃圾箱或回收站,而不是永久删除它们。
如果因程序缺陷而用send2trash
删除了某些不想删除的东西,稍后可以从垃圾箱恢复。
安装 send2trash
后,在交互式环境中输入以下代码:
import send2trash
baconFile = open('xx_bacon.txt', 'a') #creates the file
baconFile.write('Bacon is not a vegetable.')
25
baconFile.close()
send2trash.send2trash('xx_bacon.txt')
一般来说,总是应该使用 send2trash.send2trash()
函数来删除文件和文件夹。
虽然它将文件发送到垃圾箱,
让稍后能够恢复它们,但是这不像永久删除文件,
不会释放磁盘空间。如果希望程序释放磁盘空间,
就要用 os
和 shutil
来删除文件和文件夹。
请注意, send2trash()
函数只能将文件送到垃圾箱,
不能从中恢复文件。