1. shutil 模块
shutil(或称为shell 工具)模块中包含一些函数,让你在Python 程序中复制、移动、改名和删除文件。要使用shutil
的函数,首先需要import shutil。
1.1 复制文件和文件夹
调用shutil.copy(source, destination),将路径source 处的文件复制到路径destination处的文件夹(source 和
destination 都是字符串)。如果destination 是一个文件名,它将作为被复制文件的新名字。该函数返回一个字符串,
表示被复制文件的路径。
import shutil, os
os.chdir('D:\\') #os.chdir()改变当前目录
shutil.copy('D://demo1.txt', 'D:\\Jupyter Notebook\\demo2.txt')
'D:\\Jupyter Notebook\\demo2.txt'
shutil.copytree('D:\\demopack1', 'D:\\Jupyter Notebook\\demopack2')
'D:\\Jupyter Notebook\\demopack2'
第一个shutil.copy()调用将文件D://demo1.txt复制到文件夹D:\\Jupyter Notebook。返回值是刚刚被复制的文件的路径。请注意,
因为指定了一个文件夹作为目的地址,原来的文件名demo1.txt 就被用作新复制的文件名。第二个shutil.copy()调用也
将文件D://demo1.txt 复制到文件夹D:\\Jupyter Notebook,但为新文件提供了一个名字demo2.txt。
shutil.copy()将复制一个文件,shutil.copytree()将复制整个文件夹,以及它包含的文件夹和文件。调用
shutil.copytree(source, destination),将路径source 处的文件夹,包括它的所有文件和子文件夹,复制到路径
destination 处的文件夹。source 和destination 参数都是字符串。该函数返回一个字符串,是新复制的文件夹的路径。
shutil.copytree('D:\\demopack1', 'D:\\Jupyter Notebook\\demopack2')
'D:\\Jupyter Notebook\\demopack2'
1.2 文件和文件夹的移动和改名
调用shutil.move(source, destination),将路径source 处的文件夹移动到路径destination,并返回新位置的绝对路径
的字符串。
如果destination 指向一个文件夹,source 文件将移动到destination 中,并保持原来的文件名。
shutil.move('D://demo1.txt', 'D:\\Jupyter Notebook\\demopack2')
'D:\\Jupyter Notebook\\demopack2\\demo1.txt'
如果目的文件夹中已存在了该文件, 则它会被覆盖。因为这种方式很容易不小心覆盖文件, 所以使用move()时应注意。
destination路径也可以指定一个文件名, source文件被移动并改名.
shutil.move('D://demo1.txt', 'D:\\Jupyter Notebook\\new_demo1.txt')
'D:\\Jupyter Notebook\\new_demo1.txt'
前面的例子都是目的文件夹已存在的情况,如果目的文件夹不存在的话,move()就会将bacon.txt 改名,变成名为eggs 的文件。
>>> shutil.move('C:\\bacon.txt', 'C:\\eggs')
'C:\\eggs'
这里,move()在C:\目录下找不到名为eggs 的文件夹,所以假定destination 指的是一个文件,而非文件夹。所以
bacon.txt 文本文件被改名为eggs(没有.txt 文件扩展名的文本文件),但这可能不是你所希望的!这可能是程序中
很难发现的缺陷,因为move()调用会很开心地做一些事情,但和你所期望的完全不同。这也是在使用move()时要小
心的另一个理由。
最后,构成目的地的文件夹必须已经存在,否则Python 会抛出异常。
1.3 永久删除文件和文件夹
利用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)代码行的注释。然后再次
运行该程序,实际删除这些文件。
1.4 用send2trash 模块安全地删除
因为Python 内建的shutil.rmtree()函数不可恢复地删除文件和文件夹,所以用起来可能有危险。删除文件和文件夹
的更好方法,是使用第三方的send2trash 模块。
利用send2trash,比Python 常规的删除函数要安全得多,因为它会将文件夹和文件发送到计算机的垃圾箱或回收
站,而不是永久删除它们。如果因程序缺陷而用send2trash 删除了某些你不想删除的东西,稍后可以从垃圾箱恢复。
2. 遍历目录树
假定你希望对某个文件夹中的所有文件改名,包括该文件夹中所有子文件夹中的所有文件。也就是说,你希望遍
历目录树,处理遇到的每个文件。写程序完成这件事,可能需要一些技巧。好在,Python 提供了一个函数,替你
处理这个过程。
for folderName, subfolders, filenames in os.walk('D:\pywork\TXyiqing'):
print('The current folder is ' + folderName)
for subfolder in subfolders:
print('SUBFOLDER OF ' + folderName + ': ' + subfolder)
for filename in filenames:
print('FILE INSIDE ' + folderName + ': ' + filename)
print(' ')
The current folder is D:\pywork\TXyiqing
SUBFOLDER OF D:\pywork\TXyiqing: .idea
SUBFOLDER OF D:\pywork\TXyiqing: Include
SUBFOLDER OF D:\pywork\TXyiqing: Lib
SUBFOLDER OF D:\pywork\TXyiqing: Scripts
FILE INSIDE D:\pywork\TXyiqing: pyvenv.cfg
FILE INSIDE D:\pywork\TXyiqing: spider.py
FILE INSIDE D:\pywork\TXyiqing: SQLdb.py
The current folder is D:\pywork\TXyiqing\.idea
SUBFOLDER OF D:\pywork\TXyiqing\.idea: dictionaries
SUBFOLDER OF D:\pywork\TXyiqing\.idea: inspectionProfiles
FILE INSIDE D:\pywork\TXyiqing\.idea: misc.xml
FILE INSIDE D:\pywork\TXyiqing\.idea: modules.xml
FILE INSIDE D:\pywork\TXyiqing\.idea: TXyiqing.iml
FILE INSIDE D:\pywork\TXyiqing\.idea: workspace.xml
The current folder is D:\pywork\TXyiqing\.idea\dictionaries
FILE INSIDE D:\pywork\TXyiqing\.idea\dictionaries: ChaosA.xml
The current folder is D:\pywork\TXyiqing\.idea\inspectionProfiles
FILE INSIDE D:\pywork\TXyiqing\.idea\inspectionProfiles: Project_Default.xml
os.walk()函数被传入一个字符串值,即一个文件夹的路径。你可以在一个for
循环语句中使用os.walk()函数,遍历目录树,就像使用range()函数遍历一个范围的
数字一样。不像range(),os.walk()在循环的每次迭代中,返回3 个值:
1.当前文件夹名称的字符串。
2.当前文件夹中子文件夹的字符串的列表。
3.当前文件夹中文件的字符串的列表。
所谓当前文件夹,是指for 循环当前迭代的文件夹。程序的当前工作目录,不会因为os.walk()而改变。就像你可以
在代码for i in range(10):中选择变量名称i 一样,你也可以选择前面列出来的3 个字的变量名称。我通常使用
foldername、subfolders 和filenames。
3. 用zipfile 模块压缩文件
3.1 读取ZIP文件
要读取ZIP 文件的内容,首先必须创建一个ZipFile 对象(请注意大写首字母Z和F)。ZipFile 对象在概念上与File
对象相似,你在第8 章中曾经看到open()函数返回File 对象:它们是一些值,程序通过它们与文件打交道。要创建
一个ZipFile对象,就调用zipfile.ZipFile()函数,向它传入一个字符串,表示.zip 文件的文件名。
请注意,zipfile 是Python 模块的名称,ZipFile()是函数的名称。
import zipfile, os
os.chdir('D:\\')
exampleZip = zipfile.ZipFile('example.zip')
exampleZip.namelist()
['cats/catnames.txt', 'cats/zophie.jpg', 'spam.txt', 'cats/']
spamInfo = exampleZip.getinfo('spam.txt')
spamInfo.file_size
0
spamInfo.compress_size
0
ZipFile 对象有一个namelist()方法,返回ZIP 文件中包含的所有文件和文件夹的字符串的列表。这些字符串可以传
递给ZipFile 对象的getinfo()方法,返回一个关于特定文件的ZipInfo 对象。ZipInfo 对象有自己的属性,诸如表示字
节数的file_size和compress_size,它们分别表示原来文件大小和压缩后文件大小。ZipFile 对象表示整个归档文
件,而ZipInfo 对象则保存该归档文件中每个文件的有用信息。
3.2 从ZIP中解压缩
ZipFile 对象的extractall()方法从ZIP 文件中解压缩所有文件和文件夹,放到当前工作目录中。
import zipfile, os
os.chdir('D:\\')
exampleZip = zipfile.ZipFile('example.zip')
exampleZip.extractall()
exampleZip.close()
运行这段代码后, example.zip的内容被解压到D:\。或者,你可以想extractall()传递一个文件夹名称, 它将解压
缩到那个文件夹,而不是当前工作目录。如果传递给extractall()方法的文件夹不存在, 它会被创建。
ZipFile对象的extract()方法从ZIP文件中解压缩单个文件
import zipfile, os
os.chdir('D:\\')
exampleZip = zipfile.ZipFile('example.zip')
exampleZip.extract('spam.txt')
'D:\\spam.txt'
exampleZip.extract('spam.txt', 'D:\Jupyter Notebook')
'D:\\Jupyter Notebook\\spam.txt'
exampleZip.close()
传递给extract()的字符串,必须匹配namelist()返回的字符串列表中的一个。或者,你可以向extract()传递第二个参
数,将文件解压缩到指定的文件夹,而不是当前工作目录。如果第二个参数指定的文件夹不存在,Python 就会创
建它。extract()的返回值是被压缩后文件的绝对路径。
3.3 创建和添加ZIP文件
要创建你自己的压缩ZIP 文件,必须以“写模式”打开ZipFile 对象,即传入'w'作为第二个参数(这类似于向open()
函数传入'w',以写模式打开一个文本文件)。如果向ZipFile 对象的write()方法传入一个路径,Python 就会压缩该
路径所指的文件,将它加到ZIP 文件中。write()方法的第一个参数是一个字符串,代表要添加的文件名。第二个参
数是“压缩类型”参数,它告诉计算机使用怎样的算法来压缩文件。可以总是将这个值设置为
zipfile.ZIP_DEFLATED(这指定了deflate 压缩算法,它对各种类型的数据都很有效)
newZip = zipfile.ZipFile('new.zip', 'w')
newZip.write('spam.txt', compress_type = zipfile.ZIP_DEFLATED)
newZip.close()