第88集:目录操作
学习目标
- 掌握目录的创建、删除、重命名等基本操作
- 理解目录遍历的方法
- 学会使用os和pathlib模块进行目录操作
- 掌握递归目录操作
- 了解目录操作的最佳实践和注意事项
一、目录操作基础
1.1 什么是目录
目录(Directory)是文件系统中用于组织文件和子目录的容器。在Python中,目录操作是文件系统操作的重要组成部分。
1.2 目录操作的重要性
- 组织和管理文件
- 实现文件系统的层次结构
- 批量处理文件
- 实现文件备份和同步
二、os模块的目录操作
os模块提供了传统的目录操作方法,是Python标准库中最常用的文件系统操作模块。
2.1 创建目录
os.mkdir()
创建单个目录,如果父目录不存在会报错。
import os
# 创建单个目录
os.mkdir('new_folder')
# 如果目录已存在会报错
try:
os.mkdir('existing_folder')
except FileExistsError:
print("目录已存在")os.makedirs()
递归创建多级目录,如果父目录不存在会自动创建。
import os
# 创建多级目录
os.makedirs('parent/child/grandchild')
# 如果目录已存在会报错
try:
os.makedirs('existing/path')
except FileExistsError:
print("目录已存在")
# 使用exist_ok参数避免报错
os.makedirs('existing/path', exist_ok=True)2.2 删除目录
os.rmdir()
删除空目录,如果目录不为空会报错。
import os
# 删除空目录
os.rmdir('empty_folder')
# 如果目录不为空会报错
try:
os.rmdir('non_empty_folder')
except OSError as e:
print(f"删除失败: {e}")os.removedirs()
递归删除空目录,从最内层开始删除。
import os
# 删除多级空目录
os.removedirs('parent/child/grandchild')
# 如果目录不为空会停止删除shutil.rmtree()
删除目录及其所有内容(包括子目录和文件)。
import shutil
# 删除目录树
shutil.rmtree('folder_to_delete')
# 注意:此操作不可逆,使用时要谨慎2.3 切换工作目录
os.chdir()
改变当前工作目录。
import os
# 获取当前工作目录
print(os.getcwd())
# 切换工作目录
os.chdir('/path/to/directory')
# 切换回上级目录
os.chdir('..')
# 切换回用户主目录
os.chdir(os.path.expanduser('~'))2.4 获取目录列表
os.listdir()
返回指定目录下的所有条目(文件和目录)列表。
import os
# 获取当前目录内容
items = os.listdir('.')
print(items)
# 获取指定目录内容
items = os.listdir('/path/to/directory')
# 只获取文件
files = [f for f in os.listdir('.') if os.path.isfile(f)]
# 只获取目录
dirs = [d for d in os.listdir('.') if os.path.isdir(d)]os.scandir()
返回目录条目的迭代器,比os.listdir()更高效。
import os
# 使用scandir遍历目录
with os.scandir('.') as entries:
for entry in entries:
if entry.is_file():
print(f"文件: {entry.name}")
elif entry.is_dir():
print(f"目录: {entry.name}")2.5 目录重命名和移动
os.rename()
重命名文件或目录,或移动文件或目录。
import os
# 重命名目录
os.rename('old_name', 'new_name')
# 移动目录(在同一文件系统内)
os.rename('folder/old_name', 'folder/subfolder/new_name')os.renames()
递归重命名或移动目录。
import os
# 递归重命名
os.renames('old/path', 'new/path')shutil.move()
移动文件或目录,支持跨文件系统。
import shutil
# 移动目录
shutil.move('source_folder', 'destination_folder')
# 移动并重命名
shutil.move('source_folder', 'destination/new_name')2.6 目录信息查询
os.getcwd()
获取当前工作目录。
import os
cwd = os.getcwd()
print(f"当前工作目录: {cwd}")os.path.isdir()
检查路径是否为目录。
import os
if os.path.isdir('/path/to/folder'):
print("这是一个目录")三、pathlib模块的目录操作
pathlib模块提供了面向对象的目录操作接口,更加现代和直观。
3.1 创建目录
from pathlib import Path
# 创建单个目录
Path('new_folder').mkdir()
# 创建多级目录
Path('parent/child/grandchild').mkdir(parents=True)
# 创建目录,如果已存在不报错
Path('existing_folder').mkdir(exist_ok=True)
# 组合使用
Path('parent/child').mkdir(parents=True, exist_ok=True)3.2 删除目录
from pathlib import Path
# 删除空目录
Path('empty_folder').rmdir()
# 删除目录树(需要shutil)
import shutil
shutil.rmtree('folder_to_delete')3.3 遍历目录
iterdir()
遍历目录内容。
from pathlib import Path
# 遍历目录
folder = Path('documents')
for item in folder.iterdir():
if item.is_file():
print(f"文件: {item.name}")
elif item.is_dir():
print(f"目录: {item.name}")glob()
查找匹配模式的文件和目录。
from pathlib import Path
# 查找所有Python文件
python_files = list(Path('.').glob('*.py'))
# 查找所有目录
dirs = list(Path('.').glob('*/'))
# 查找特定模式的文件
files = list(Path('.').glob('data_*.csv'))rglob()
递归查找匹配模式的文件和目录。
from pathlib import Path
# 递归查找所有Python文件
all_python_files = list(Path('.').rglob('*.py'))
# 递归查找所有目录
all_dirs = list(Path('.').rglob('*/'))3.4 目录操作示例
from pathlib import Path
# 创建目录结构
project = Path('my_project')
project.mkdir(exist_ok=True)
(project / 'src').mkdir(exist_ok=True)
(project / 'tests').mkdir(exist_ok=True)
(project / 'docs').mkdir(exist_ok=True)
# 遍历目录树
for item in project.rglob('*'):
if item.is_file():
print(f"文件: {item.relative_to(project)}")
elif item.is_dir():
print(f"目录: {item.relative_to(project)}")四、目录遍历
4.1 使用os.walk()
os.walk()是递归遍历目录树的强大工具。
import os
# 基本用法
for root, dirs, files in os.walk('directory'):
print(f"根目录: {root}")
print(f"子目录: {dirs}")
print(f"文件: {files}")
print("-" * 50)os.walk()参数详解
- topdown: True表示从上到下遍历(默认),False表示从下到上
- onerror: 处理错误的回调函数
- followlinks: 是否跟随符号链接
import os
# 从下到上遍历
for root, dirs, files in os.walk('directory', topdown=False):
print(f"处理目录: {root}")
# 处理错误
def handle_error(error):
print(f"错误: {error}")
for root, dirs, files in os.walk('directory', onerror=handle_error):
pass
# 跟随符号链接
for root, dirs, files in os.walk('directory', followlinks=True):
pass4.2 使用pathlib递归遍历
from pathlib import Path
# 使用rglob递归遍历
for item in Path('directory').rglob('*'):
if item.is_file():
print(f"文件: {item}")
elif item.is_dir():
print(f"目录: {item}")
# 只遍历文件
for file in Path('directory').rglob('*'):
if file.is_file():
print(file)
# 只遍历目录
for dir in Path('directory').rglob('*/'):
print(dir)4.3 自定义递归遍历
from pathlib import Path
def traverse_directory(path, depth=0):
"""递归遍历目录"""
indent = " " * depth
print(f"{indent}{path.name}/")
for item in path.iterdir():
if item.is_dir():
traverse_directory(item, depth + 1)
else:
print(f"{indent} {item.name}")
# 使用
traverse_directory(Path('my_project'))五、目录操作的实际应用
5.1 创建项目目录结构
from pathlib import Path
def create_project_structure(project_name):
"""创建标准项目目录结构"""
project = Path(project_name)
# 创建主目录
project.mkdir(exist_ok=True)
# 创建子目录
subdirs = ['src', 'tests', 'docs', 'data', 'output']
for subdir in subdirs:
(project / subdir).mkdir(exist_ok=True)
print(f"项目结构已创建: {project}")
# 使用
create_project_structure('my_new_project')5.2 清理空目录
from pathlib import Path
def remove_empty_dirs(root_dir):
"""递归删除空目录"""
root = Path(root_dir)
# 从下到上遍历
for dir_path in sorted(root.rglob('*'), reverse=True):
if dir_path.is_dir():
try:
dir_path.rmdir()
print(f"删除空目录: {dir_path}")
except OSError:
pass # 目录不为空,跳过
# 使用
remove_empty_dirs('my_project')5.3 复制目录结构
import shutil
from pathlib import Path
def copy_directory_structure(src, dst):
"""复制目录结构(不复制文件)"""
src_path = Path(src)
dst_path = Path(dst)
for dir_path in src_path.rglob('*/'):
relative = dir_path.relative_to(src_path)
new_dir = dst_path / relative
new_dir.mkdir(parents=True, exist_ok=True)
print(f"创建目录: {new_dir}")
# 使用
copy_directory_structure('source', 'destination')5.4 统计目录信息
from pathlib import Path
def analyze_directory(path):
"""分析目录信息"""
root = Path(path)
total_files = 0
total_dirs = 0
total_size = 0
for item in root.rglob('*'):
if item.is_file():
total_files += 1
total_size += item.stat().st_size
elif item.is_dir():
total_dirs += 1
print(f"目录: {root}")
print(f"文件总数: {total_files}")
print(f"目录总数: {total_dirs}")
print(f"总大小: {total_size / 1024:.2f} KB")
# 使用
analyze_directory('my_project')5.5 查找大文件
from pathlib import Path
def find_large_files(directory, size_mb=10):
"""查找大于指定大小的文件"""
root = Path(directory)
size_threshold = size_mb * 1024 * 1024
large_files = []
for file in root.rglob('*'):
if file.is_file():
file_size = file.stat().st_size
if file_size > size_threshold:
large_files.append((file, file_size))
# 按大小排序
large_files.sort(key=lambda x: x[1], reverse=True)
print(f"大于 {size_mb} MB 的文件:")
for file, size in large_files:
print(f"{file.relative_to(root)}: {size / 1024 / 1024:.2f} MB")
# 使用
find_large_files('my_project', size_mb=1)5.6 同步目录
import shutil
from pathlib import Path
def sync_directories(src, dst):
"""同步两个目录"""
src_path = Path(src)
dst_path = Path(dst)
# 确保目标目录存在
dst_path.mkdir(parents=True, exist_ok=True)
# 复制源目录中的所有文件
for item in src_path.rglob('*'):
if item.is_file():
relative = item.relative_to(src_path)
dest_file = dst_path / relative
# 创建目标文件的父目录
dest_file.parent.mkdir(parents=True, exist_ok=True)
# 复制文件
shutil.copy2(item, dest_file)
print(f"复制: {relative}")
# 使用
sync_directories('source', 'backup')六、目录操作的最佳实践
6.1 使用上下文管理器
import os
# 改变工作目录后自动恢复
original_cwd = os.getcwd()
try:
os.chdir('/path/to/directory')
# 执行操作
finally:
os.chdir(original_cwd)6.2 使用exist_ok参数
from pathlib import Path
# 避免目录已存在错误
Path('folder').mkdir(exist_ok=True)6.3 使用parents参数创建多级目录
from pathlib import Path
# 一次性创建多级目录
Path('parent/child/grandchild').mkdir(parents=True, exist_ok=True)6.4 使用try-except处理错误
from pathlib import Path
try:
Path('folder').rmdir()
except OSError as e:
print(f"删除失败: {e}")6.5 使用pathlib而不是os
# 推荐
from pathlib import Path
Path('folder/file.txt').parent.mkdir(parents=True, exist_ok=True)
# 不推荐
import os
os.makedirs(os.path.dirname('folder/file.txt'), exist_ok=True)6.6 谨慎使用rmtree
import shutil
# 删除前确认
import sys
if input("确定要删除目录吗?(y/n): ").lower() == 'y':
shutil.rmtree('folder')
else:
print("取消删除")七、常见问题与解决方案
7.1 目录不存在错误
问题:操作目录时提示目录不存在
解决方案:
from pathlib import Path
# 检查目录是否存在
if not Path('folder').exists():
Path('folder').mkdir(parents=True)7.2 权限错误
问题:没有权限创建或删除目录
解决方案:
from pathlib import Path
try:
Path('folder').mkdir()
except PermissionError:
print("没有权限创建目录")7.3 目录不为空错误
问题:删除目录时提示目录不为空
解决方案:
import shutil
# 使用shutil.rmtree删除非空目录
shutil.rmtree('folder')7.4 路径分隔符问题
问题:在不同操作系统上路径分隔符不同
解决方案:
from pathlib import Path
# 使用pathlib自动处理跨平台路径
path = Path('folder') / 'subfolder' / 'file.txt'7.5 符号链接循环
问题:遍历目录时遇到符号链接循环
解决方案:
import os
# 不跟随符号链接
for root, dirs, files in os.walk('directory', followlinks=False):
pass八、总结
目录操作是Python文件系统操作的核心技能。本集我们学习了:
- os模块:传统的目录操作方法
- pathlib模块:现代的面向对象目录操作
- 目录遍历:os.walk()和pathlib的递归遍历
- 实际应用:创建项目结构、清理空目录、同步目录等
- 最佳实践:使用pathlib、错误处理、谨慎删除
掌握这些技能将帮助你有效地管理文件系统,实现各种文件操作需求。
九、练习题
- 编写一个函数,递归创建指定的目录结构
- 实现一个函数,统计指定目录及其子目录中的文件数量和总大小
- 编写代码,查找并删除指定目录下的所有空目录
- 实现一个函数,复制目录结构(不复制文件内容)
- 编写一个脚本,同步两个目录的内容
- 实现一个函数,查找指定目录下所有大于10MB的文件
- 编写代码,创建一个标准的Python项目目录结构
- 实现一个函数,递归遍历目录并打印目录树结构