You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用os.walk遍历外部驱动器时遇冻结错误,如何解决?

解决os.walk遍历外部驱动器冻结问题并实现路径规范化

问题背景

需要对外部驱动器中的文件路径进行规范化(去除重音),使用os.walk()时脚本出现冻结,强制终止后抛出如下错误:

^CTraceback (most recent call last):
  File "~/normalize_filepaths.py", line 2
    for root, dirs, files in os.walk(target, topdown = False):
  File "<frozen os>", line 377, in walk
KeyboardInterrupt

相关代码片段:

import os
import unicodedata
import shutil

def normalize(fp):
    """
    >>> normalize("/Volumes/MM_BUP/MIGUEL/Acólitos")
    '/Volumes/MM_BUP/MIGUEL/Acolitos'
    >>> normalize("/Volumes/MM_BUP/MIGUEL/Acólitos")
    '/Volumes/MM_BUP/MIGUEL/Acolitos'
    >>> normalize("'This is my cup.' _ ゼロコ ZEROKO _ 紅茶の遊び方 _ mime _ clowning-8MgRJAXn1tE.mp4")
    "'This is my cup.' _  ZEROKO _  _ mime _ clowning-8MgRJAXn1tE.mp4"
    >>> normalize(" großer Tag")
    ' grosser Tag'
    """

    fp = fp.replace("ß", "ss")
    
    name_clean = unicodedata.normalize('NFD', fp)
    return name_clean.encode('ascii', 'ignore').decode("ascii")


def main(target="/some/path"):
    for root, dirs, files in os.walk(target, topdown = False):
        for name in files + dirs:
            filepath = os.path.join(root, name)
            clean = normalize(name)
            new_filepath = os.path.join(root, clean)
            shutil.move(filepath, new_filepath)

解决方案及优化点

1. 切换topdown=True遍历模式

topdown=False会先处理子目录再处理父目录,重命名父目录后会导致已遍历的子目录路径失效,引发遍历混乱甚至卡住。改为topdown=True后,可动态修改dirs列表,确保遍历路径始终正确。

2. 拆分文件与目录处理逻辑

单独处理文件和目录,避免混合处理导致的路径冲突;对目录重命名后更新dirs列表,让后续遍历使用新的目录名。

3. 增加错误处理与跳过逻辑

外部驱动器可能存在文件锁定、权限不足或系统特殊文件,添加try-except捕获异常,记录错误后继续执行,防止脚本因单个文件/目录出错而卡住。

4. 避免重复操作

先判断原路径和新路径是否一致,一致则跳过移动操作,减少不必要的IO开销。

5. 添加进度输出

打印当前处理的文件/目录,直观了解脚本运行状态,避免误以为脚本冻结。

修改后的完整代码

import os
import unicodedata
import shutil

def normalize(fp):
    """
    >>> normalize("/Volumes/MM_BUP/MIGUEL/Acólitos")
    '/Volumes/MM_BUP/MIGUEL/Acolitos'
    >>> normalize("/Volumes/MM_BUP/MIGUEL/Acólitos")
    '/Volumes/MM_BUP/MIGUEL/Acolitos'
    >>> normalize("'This is my cup.' _ ゼロコ ZEROKO _ 紅茶の遊び方 _ mime _ clowning-8MgRJAXn1tE.mp4")
    "'This is my cup.' _  ZEROKO _  _ mime _ clowning-8MgRJAXn1tE.mp4"
    >>> normalize(" großer Tag")
    ' grosser Tag'
    """

    fp = fp.replace("ß", "ss")
    
    name_clean = unicodedata.normalize('NFD', fp)
    return name_clean.encode('ascii', 'ignore').decode("ascii")

def process_item(root, name):
    original_path = os.path.join(root, name)
    clean_name = normalize(name)
    new_path = os.path.join(root, clean_name)
    
    if original_path == new_path:
        return
    
    try:
        shutil.move(original_path, new_path)
        print(f"Processed: {original_path} -> {new_path}")
    except Exception as e:
        print(f"Error processing {original_path}: {str(e)}")

def main(target="/some/path"):
    for root, dirs, files in os.walk(target, topdown=True):
        # 处理文件
        for name in files:
            process_item(root, name)
        # 处理目录并更新dirs
        updated_dirs = []
        for name in dirs:
            original_path = os.path.join(root, name)
            clean_name = normalize(name)
            new_path = os.path.join(root, clean_name)
            if original_path != new_path:
                try:
                    shutil.move(original_path, new_path)
                    print(f"Renamed directory: {original_path} -> {new_path}")
                    updated_dirs.append(clean_name)
                except Exception as e:
                    print(f"Error renaming directory {original_path}: {str(e)}")
                    updated_dirs.append(name)
            else:
                updated_dirs.append(name)
        dirs[:] = updated_dirs

if __name__ == "__main__":
    # 替换为你的外部驱动器路径
    main(target="/Volumes/MM_BUP")

内容的提问来源于stack exchange,提问作者ginjaemocoes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 23:44:52