>>> from env_helper import info; info()
页面更新时间: 2023-06-30 19:18:04
运行环境:
    Linux发行版本: Debian GNU/Linux 12 (bookworm)
    操作系统内核: Linux-6.1.0-9-amd64-x86_64-with-glibc2.36
    Python版本: 3.11.2

3.3. 使用 shutil 模块

shutil (或称为 shell 工具)模块中包含一些函数,让你在Python程序中复制、移动、改名和删除文件。 要使用 shutil 的函数,首先需要 import shutil

3.3.1. 复制文件和文件夹

shutil 模块提供了一些函数,用于复制文件和整个文件夹。

调用 shutil.copy(source,destination) , 将路径 source 处的文件复制到路径 destination 处的文件夹( sourcedestination 都是字符串)。 如果 destination 是一个文件名,它将作为被复制文件的新名字。 该函数返回一个字符串,表示被复制文件的路径。

在交互式环境中输入以下代码,看看 shutil.copy() 的效果:

>>> import shutil, os
>>> shutil.copy('./chapter.ipynb','/tmp')
'/tmp/chapter.ipynb'
>>> shutil.copy('./chapter.ipynb','/tmp/new_chapter.ipynb')
'/tmp/new_chapter.ipynb'

第一个 shutil.copy() 调用将文件 复制到文件夹 C::raw-latex:`\delicious`。返回值是刚刚被复制的文件的路径。 请注意,因为指定了一个文件夹作为目的地〇, 原来的文件名 spam.txt 就被用作新复制的文件名。 第二个 shutil.copy() 调用也将文件 C::raw-latex:`\eggs`.txt 复制到文件夹C::raw-latex:`\delicious`, 但为新文件提供了一个名字 eggs2.txt

shutil.copy() 将复制一个文件,shutil.copytree() 将复制整个文件夹,以及它包含的文件夹和文件。 调用 shutil.copytree(source,destination),将路径 source 处的文件夹, 包括它的所有文件和子文件夹,复制到路径 destination 处的文件夹。 sourcedestination 参数都是字符串。该函数返回一个字符串,是新复制的文件夹的路径。

在交互式环境中输入以下代码:

>>> if os.path.exists('/tmp/dest_backup')==False:
>>>     shutil.copytree('./', '/tmp/dest_backup')

shutil.copytree() 调用创建了一个新文件夹, 名为 dest_backup ,其中的内容与原来的 ./ 文件夹一样。 现在你已经完成了资料的备份。

3.3.2. 文件和文件夹的移动与改名

调用 shutil.move(source, destination) , 将路径 source 处的文件夹移动到路径 destination , 并返回新位置的绝对路径的字符串。 如果 destination 指向一个文件夹, source 文件将移动到 destination 中,并保持原来的文件名。 例如,在交互式环境中输入以下代码:

>>> dest_dir = '/tmp/dst'
>>> if os.path.exists(dest_dir):
>>>     pass
>>> else:
>>>     os.mkdir(dest_dir)
>>>
>>> shutil.move('/tmp/new_chapter.ipynb', '/tmp/dst')

假定在 /tmp 目录中已存在一个名为 dst 的文件夹, 这个 shutil.move() 调用就是说,将目标文件移动到文件夹 /tmp/dst 中。

如果在 /tmp/dst 中原来已经存在一个文件 new_chapter.ipynb ,它就会被覆写。 因为用这种方式很容易不小心覆写文件,所以在使用 move() 时应该注意。

destination路径也可以指定一个文件名。 在下面的例子中,source文件被移动 并改名。

>>> shutil.move('/tmp/dst/new_chapter.ipynb','/tmp/dst/new_chapter_2.ipynb')
'/tmp/dst/new_chapter_2.ipynb'

这一行是说,“将C::raw-latex:`\bacon`.txt移动到文件夹C::raw-latex:`\eggs`, 完成之后,将bacon.txt文件改名为new_bacon.txt 。”

前面两个例子都假设在C::raw-latex:`\目录下有一个文件夹eggs`。 但是如果没有eggs文件夹, move()就会将 bacon.txt 改名,变成名为 eggs 的文件。

>>> 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::raw-latex:`\目录下找不到名为eggs的文件夹`, 所以假定destination指的是一个文件,而非文件夹。 所以 bacon.txt 文本文件被改名为 eggs (没有.txt 文件扩展名的文本文件), 但这可能不是你所希望的!这可能是程序中很难发现的缺陷, 因为move() 调用会很开心地做一些事情, 但和你所期望的完全不同。这也是在使用 move() 时要小心的另一个理由。

最后,构成目的地的文件夹必须己经存在, 否则 Python 会抛出异常。

3.3.3. 永久删除文件和文件夹

利用 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) 代码行的注释。然后再次运行该程序,实际删除这些文件。

3.3.4. send2trash 模块安全地删除

因为Python内建的 shutil.rmtree() 函数 不可恢复地删除文件和文件夹,所以用起来可能有危险。 删除文件和文件夹的更好方法, 是使用第三方的 send2trash 模块。 你可以在终端窗口中运行如下命令安装该模块。

sudo apt install -y python3-send2trash

pip install send2trash

利用 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() 函数 来删除文件和文件夹。虽然它将文件发送到垃圾箱, 让你稍后能够恢复它们,但是这不像永久删除文件, 不会释放磁盘空间。如果你希望程序释放磁盘空间, 就要用 osshutil 来删除文件和文件夹。 请注意, send2trash() 函数只能将文件送到垃圾箱, 不能从中恢复文件。