pin_drop当前位置:知识文库 ❯ 图文
Python shutil模块 - 高级文件操作与目录管理
在Python中,shutil模块是高级文件操作的核心模块。与os模块不同,shutil专注于文件内容的复制、移动、删除以及目录树的整体操作。本篇教程将详细介绍shutil模块的核心功能和实际应用场景。
一、shutil模块概述
shutil(Shell Utilities的缩写)是Python的标准库之一,提供了对文件和目录集合的高级操作。当需要复制、移动或删除包含文件的整个目录时,shutil模块是最佳选择。它比os模块更适合处理需要操作文件内容的场景。
使用shutil模块前,需要先导入它:
代码示例
import shutilshutil模块与os模块互补使用:os模块处理路径和低级别操作,shutil模块处理高级别的文件复制、移动和归档操作。
二、常用语法与函数
shutil模块提供了丰富的高级文件操作函数,以下是常用的核心函数:
文件复制函数
-
shutil.copy(src, dst):复制文件内容,不保留元数据
-
shutil.copy2(src, dst):复制文件并保留完整元数据(修改时间等)
-
shutil.copyfile(src, dst):仅复制文件内容,dst必须是完整文件路径
-
shutil.copytree(src, dst):递归复制整个目录树
文件移动与删除函数
-
shutil.move(src, dst):移动文件或目录(跨文件系统时为复制+删除)
-
shutil.rmtree(path):递归删除整个目录树(包括非空目录)
磁盘与权限函数
-
shutil.disk_usage(path):获取磁盘使用情况(总计、已用、可用)
-
shutil.chown(path, user, group):修改文件所有者和组
-
shutil.which(cmd):在PATH中查找可执行文件的路径
归档压缩函数
-
shutil.make_archive(base_name, format, root_dir):创建归档文件(zip、tar等)
-
shutil.unpack_archive(filename, extract_dir):解压归档文件
三、基本用法详解
1. 复制文件
shutil模块提供了多种复制文件的方法,区别在于是否保留元数据以及目标路径的处理方式。
代码示例
import shutil
# copy() - 复制文件内容,目标可以是目录
shutil.copy('source.txt', 'destination.txt')
shutil.copy('source.txt', '/path/to/directory/')
# copy2() - 复制文件并保留元数据(推荐)
shutil.copy2('source.txt', 'destination.txt')
# copyfile() - 仅复制内容,目标必须是完整路径
shutil.copyfile('source.txt', 'destination.txt')
# copyfileobj() - 从文件对象复制到文件对象
with open('source.txt', 'rb') as fsrc:
with open('destination.txt', 'wb') as fdst:
shutil.copyfileobj(fsrc, fdst)2. 复制目录树
shutil.copytree()可以递归复制整个目录树,包括所有子目录和文件。
代码示例
import shutil
# 复制整个目录树(目标目录不能存在)
shutil.copytree('source_dir', 'destination_dir')
# 忽略特定文件或目录
shutil.copytree('source_dir', 'destination_dir',
ignore=shutil.ignore_patterns('*.pyc', '__pycache__'))
# 自定义忽略函数
def ignore_pycache_and_tests(dir, files):
return [f for f in files if f.endswith('.pyc') or f == 'tests']
shutil.copytree('source_dir', 'destination_dir',
ignore=ignore_pycache_and_tests)
# dirs_exist_ok=True 允许目标目录已存在(Python 3.8+)
shutil.copytree('source_dir', 'destination_dir', dirs_exist_ok=True)3. 移动文件和目录
shutil.move()用于移动文件或目录。在同一文件系统内是重命名操作,跨文件系统时则是复制后删除原文件。
代码示例
import shutil
# 移动文件
shutil.move('old_location.txt', 'new_location.txt')
# 移动到目录
shutil.move('file.txt', '/path/to/directory/')
# 移动并重命名
shutil.move('old_name.txt', '/path/to/new_name.txt')
# 移动整个目录
shutil.move('source_dir', 'destination_dir')4. 删除目录树
shutil.rmtree()是删除非空目录的唯一标准方法。它会递归删除目录及其所有内容。
代码示例
import shutil
# 删除整个目录树
shutil.rmtree('directory_to_delete')
# 忽略删除错误
shutil.rmtree('directory_to_delete', ignore_errors=True)
# 自定义错误处理
def error_handler(func, path, exc_info):
print(f'删除 {path} 时出错: {exc_info}')
shutil.rmtree('directory_to_delete', onerror=error_handler)5. 创建和解压归档文件
shutil模块内置了对常见压缩格式的支持,可以方便地创建和解压归档文件。
代码示例
import shutil
# 创建zip归档
shutil.make_archive('backup', 'zip', '/path/to/source_dir')
# 创建tar.gz归档
shutil.make_archive('backup', 'gztar', '/path/to/source_dir')
# 创建带前缀的归档
shutil.make_archive('my_project_v1', 'zip',
root_dir='/path/to/project',
base_dir='.')
# 解压归档文件
shutil.unpack_archive('backup.zip', '/path/to/extract_dir')
shutil.unpack_archive('backup.tar.gz', '/path/to/extract_dir')四、完整代码示例
示例1:备份目录并创建归档
代码示例
import shutil
import os
from datetime import datetime
def backup_directory(source_dir, backup_dir):
"""备份目录并创建带时间戳的zip归档"""
# 确保备份目录存在
os.makedirs(backup_dir, exist_ok=True)
# 生成带时间戳的文件名
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
archive_name = os.path.join(backup_dir, f'backup_{timestamp}')
# 创建zip归档
archive_path = shutil.make_archive(archive_name, 'zip', source_dir)
print(f'备份完成: {archive_path}')
return archive_path
# backup_directory('./my_project', './backups')示例2:同步两个目录
代码示例
import shutil
import os
def sync_directories(source, destination):
"""将源目录的内容同步到目标目录"""
os.makedirs(destination, exist_ok=True)
for item in os.listdir(source):
src_path = os.path.join(source, item)
dst_path = os.path.join(destination, item)
if os.path.isfile(src_path):
# 如果目标文件不存在或源文件更新,则复制
if not os.path.exists(dst_path) or \
os.path.getmtime(src_path) > os.path.getmtime(dst_path):
shutil.copy2(src_path, dst_path)
print(f'已更新: {item}')
elif os.path.isdir(src_path):
# 递归同步子目录
sync_directories(src_path, dst_path)
# sync_directories('./source', './destination')示例3:清理临时文件
代码示例
import shutil
import os
def clean_temp_directory(temp_dir, max_age_days=7):
"""清理超过指定天数的临时文件"""
import time
current_time = time.time()
max_age_seconds = max_age_days * 24 * 60 * 60
for item in os.listdir(temp_dir):
item_path = os.path.join(temp_dir, item)
try:
# 获取文件修改时间
file_age = current_time - os.path.getmtime(item_path)
if file_age > max_age_seconds:
if os.path.isfile(item_path):
os.remove(item_path)
print(f'已删除文件: {item}')
elif os.path.isdir(item_path):
shutil.rmtree(item_path)
print(f'已删除目录: {item}')
except Exception as e:
print(f'处理 {item} 时出错: {e}')
# clean_temp_directory('./temp', max_age_days=7)示例4:批量移动文件
代码示例
import shutil
import os
def move_files_by_extension(source_dir, dest_dir, extension):
"""根据扩展名批量移动文件"""
os.makedirs(dest_dir, exist_ok=True)
moved_count = 0
for filename in os.listdir(source_dir):
if filename.endswith(extension):
src = os.path.join(source_dir, filename)
dst = os.path.join(dest_dir, filename)
shutil.move(src, dst)
moved_count += 1
print(f'已移动: {filename}')
print(f'共移动了 {moved_count} 个文件')
# move_files_by_extension('./downloads', './images', '.jpg')
# move_files_by_extension('./downloads', './documents', '.pdf')示例5:获取磁盘使用信息
代码示例
import shutil
def display_disk_usage(path='/'):
"""显示指定路径的磁盘使用情况"""
usage = shutil.disk_usage(path)
# 转换为GB
total_gb = usage.total / (1024 ** 3)
used_gb = usage.used / (1024 ** 3)
free_gb = usage.free / (1024 ** 3)
percent_used = (usage.used / usage.total) * 100
print(f'路径: {path}')
print(f'总容量: {total_gb:.2f} GB')
print(f'已使用: {used_gb:.2f} GB ({percent_used:.1f}%)')
print(f'可用空间: {free_gb:.2f} GB')
# display_disk_usage('C:/') # Windows
# display_disk_usage('/') # Linux/macOS示例6:安全的文件复制(带进度提示)
代码示例
import shutil
import os
def copy_with_progress(src, dst):
"""带进度提示的文件复制"""
file_size = os.path.getsize(src)
with open(src, 'rb') as fsrc:
with open(dst, 'wb') as fdst:
copied = 0
while True:
# 每次读取1MB
chunk = fsrc.read(1024 * 1024)
if not chunk:
break
fdst.write(chunk)
copied += len(chunk)
# 显示进度
progress = (copied / file_size) * 100
print(f'\r进度: {progress:.1f}%', end='')
print('\n复制完成!')
# copy_with_progress('large_file.zip', 'backup/large_file.zip')五、注意事项与最佳实践
注意1:
shutil.copytree()默认要求目标目录不存在。在Python 3.8+中,可以使用dirs_exist_ok=True参数来允许目标目录已存在。
注意2:
shutil.rmtree()是不可逆的删除操作,会永久删除整个目录树。执行前务必仔细检查路径,建议先使用os.path.exists()验证路径,并考虑添加用户确认步骤。
注意3:复制大文件时,建议使用
shutil.copyfileobj()并指定缓冲区大小,以便更好地控制内存使用和提供进度反馈。
注意4:
shutil.move()在跨文件系统移动文件时,实际上是先复制再删除源文件。如果复制过程中断,可能导致源文件和目标文件同时存在。建议在移动大文件前检查磁盘空间。
小贴士
如果需要保留文件的完整元数据(包括权限、修改时间、访问时间等),始终使用shutil.copy2()而不是shutil.copy()。copy2()在备份场景下尤为重要,因为它能确保备份文件与原始文件的时间戳一致。
六、shutil与os对比
shutil模块和os模块都涉及文件操作,但它们的侧重点不同。理解两者的区别有助于选择合适的工具:
七、小结
-
shutil模块专注于高级文件操作,是复制、移动和删除文件的最佳选择
-
shutil.copy2()比copy()更推荐,因为它保留了文件的完整元数据
-
shutil.rmtree()是删除非空目录的标准方法,操作不可逆需谨慎
-
shutil.copytree()支持忽略模式和dirs_exist_ok参数,灵活控制复制行为
-
shutil.make_archive()和unpack_archive()提供了便捷的归档压缩功能
-
shutil.move()支持跨文件系统移动,但大文件移动前需检查磁盘空间
八、练习题
练习1
编写一个函数sync_backup(source, backup_dir, max_backups=5),实现自动备份功能:将源目录备份到指定目录,每次备份创建带时间戳的zip文件,并自动删除超过max_backups数量的旧备份。
练习2
编写一个函数organize_downloads(download_dir),扫描下载目录中的文件,根据文件扩展名自动创建对应的子目录(如images、documents、videos等),并将文件移动到相应的子目录中。
常见问题
shutil.copy()和shutil.copy2()有什么区别?
shutil.copy()只复制文件内容和新文件的权限,不保留原始文件的元数据(如修改时间、访问时间)。shutil.copy2()会尽可能保留所有文件元数据,包括修改时间和访问时间。在备份场景下,推荐使用copy2()以确保备份文件与原始文件的时间戳一致。
shutil.move()和os.rename()有什么区别?
os.rename()只能在同一个文件系统内重命名或移动文件,跨文件系统时会失败。shutil.move()则更智能,在同一文件系统内使用rename,跨文件系统时自动执行复制+删除操作。因此,shutil.move()更加通用和可靠。
如何安全地删除一个可能包含只读文件的目录?
可以使用shutil.rmtree()的onerror参数来自定义错误处理函数。在Windows上,只读文件可能导致删除失败。可以编写一个错误处理函数,在遇到权限错误时先修改文件权限再重试删除。或者使用ignore_errors=True参数忽略所有错误(但这样可能无法完全删除目录)。
shutil支持哪些归档格式?
shutil.make_archive()支持的格式取决于系统安装的库。常见的包括:zip(需要zlib)、tar(内置)、gztar(gzip压缩的tar,需要zlib)、bztar(bzip2压缩的tar,需要bz2)、xztar(xz压缩的tar,需要lzma)。可以使用shutil.get_archive_formats()查看系统支持的所有格式。
本文涉及AI创作
内容由AI创作,请仔细甄别