第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):
    pass

4.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文件系统操作的核心技能。本集我们学习了:

  1. os模块:传统的目录操作方法
  2. pathlib模块:现代的面向对象目录操作
  3. 目录遍历:os.walk()和pathlib的递归遍历
  4. 实际应用:创建项目结构、清理空目录、同步目录等
  5. 最佳实践:使用pathlib、错误处理、谨慎删除

掌握这些技能将帮助你有效地管理文件系统,实现各种文件操作需求。

九、练习题

  1. 编写一个函数,递归创建指定的目录结构
  2. 实现一个函数,统计指定目录及其子目录中的文件数量和总大小
  3. 编写代码,查找并删除指定目录下的所有空目录
  4. 实现一个函数,复制目录结构(不复制文件内容)
  5. 编写一个脚本,同步两个目录的内容
  6. 实现一个函数,查找指定目录下所有大于10MB的文件
  7. 编写代码,创建一个标准的Python项目目录结构
  8. 实现一个函数,递归遍历目录并打印目录树结构
« 上一篇 文件路径操作 下一篇 » 文件压缩与解压