如何用Python创建并写入新文件。 你的程序也可以组织硬盘上已经存在的文件。 也许你曾经经历过查找一个文件夹,里面有几十个、 几百个,甚至上千个文件,需要手工进行复制、改名、 移动或压缩。或者考虑下面这样的 任务:
在一个文件夹及其所有子文件夹中,复制所有的pdf文件(且只复制pdf文件)
针对一个文件夹中的所有文件,删除文件名中前导的零,该文件夹中有数百个文件,名为spam001.txt、spam002.txt、spam003.txt等。
将几个文件夹的内容压缩到一个ZIP文件中(这可能是一个简单的备份系统)
所有这种无聊的任务,正是在请求用Python实现自动化。 通过对电脑编程来完成这些任务, 你就把它变成了一个快速工作的文件职员,而且从不犯错。
在开始处理文件时你会发现,如果能够很快查看文件的扩展名( .txt 、 .pdf 、 .jpg 等),是很有帮助的。 在 OS X 和 Linux 上,文件浏览器很有可能自动显示扩展名。
在 Windows 上,文件扩展名可能默认是隐藏的。 要显示扩展名,请点开 Start►Control Panel►Appearance 和 Personalization►Folder 选项。 在 View 选项卡中, Advanced Settings 之下,取消 Hide extensions for known file types 复选框。
shutil (或称为 shell 工具) 模块中包含一些函数,让你在Python程序中复制、 移动、改名和删除文件。要使用 shutil 的函数, 首先需要 import shutil 。
shutil 模块提供了一些函数,用于复制文件和整个文件夹。
调用 shutil.copy(source,destination) , 将路径 source 处的文件复制到路径 destination 处的文件夹( source 和 destination 都是字符串)。 如果 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 处的文件夹。 source 和 destination 参数都是字符串。该函数返回一个字符串,是新复制的文件夹的路径。
在交互式环境中输入以下代码:
if os.path.exists(‘/tmp/dest_backup’)==False:
shutil.copytree(‘./’, ‘/tmp/dest_backup’)
shutil.copytree() 调用创建了一个新文件夹, 名为 dest_backup ,其中的内容与原来的 ./ 文件夹一样。 现在你已经完成了资料的备份。
调用 shutil.move(source, destination) , 将路径 source 处的文件夹移动到路径 destination , 并返回新位置的绝对路径的字符串。 如果 destination 指向一个文件夹, source 文件将移动到 destination 中,并保持原来的文件名。 例如,在交互式环境中输入以下代码:
import os,shutil
from pathlib import Path
os.chdir(‘/home/shaopp/jubook/’)
my_file = Path(“chd3_test/bacon_backup/sec01_shutil模块.ipynb”)
if my_file.is_file():
shutil.move(‘chd3_test/bacon_backup/sec01_shutil模块.ipynb’, ‘chd3_test/sec01_shutil模块.ipynb’)
FileNotFoundError Traceback (most recent call last)
Cell In [13], line 3
1 import os,shutil
2 from pathlib import Path
----> 3 os.chdir(‘/home/shaopp/jubook/’)
4 my_file = Path(“chd3_test/bacon_backup/sec01_shutil模块.ipynb”)
5 if my_file.is_file():
FileNotFoundError: [Errno 2] No such file or directory: ‘/home/shaopp/jubook/’
假定在C::raw-latex:\目录中已存在一个名为
\ eggs
的文件夹, 这个 shutil.move() 调用就是说, “将 C::raw-latex:\bacon
.txt 移动到文件夹 C::raw-latex:eggs
中。
如果在 C::raw-latex:\eggs
中原来已经存在一个文件 bacon.txt , 它就会被覆写。因为用这种方式很容易不小心覆写文件, 所以在使用 move()
时应该注意。
destination路径也可以指定一个文件名。 在下面的例子中,source文件被移动 并改名。
my_files = Path(“chd3_test/bacon_backup/sec02_遍历目录树.ipynb”)
if my_files.is_file():
shutil.move(‘chd3_test/bacon_backup/sec02_遍历目录树.ipynb’,‘/home/shaopp/jubook/chd3_test/sec02_遍历目录树.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 会抛出异常。
利用 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) 代码行的注释。然后再次运行该程序,实际删除这些文件。
因为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.’)
baconFile.close()
send2trash.send2trash(‘bacon.txt’)
一般来说,总是应该使用 send2trash.send2trash() 函数 来删除文件和文件夹。虽然它将文件发送到垃圾箱, 让你稍后能够恢复它们,但是这不像永久删除文件, 不会释放磁盘空间。如果你希望程序释放磁盘空间, 就要用 os 和 shutil 来删除文件和文件夹。 请注意, send2trash() 函数只能将文件送到垃圾箱, 不能从中恢复文件。