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

使用Python Watchdog库报错:'nt.DirEntry'对象无'rstrip'属性

音频文件自动移动脚本 AttributeError 问题解决

参考YouTube教程写了个音频文件自动移动脚本,用scandir和watchdog实现功能,但运行时一直报AttributeError,提示'nt.DirEntry'对象不存在'rstrip'属性,自己调整代码后还是解决不了,求帮忙。脚本代码如下:

from os import scandir, rename
from os.path import splitext, exists, join
from shutil import move
import time

import logging

from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

source_dir=r'*censored*'
mp3_dir=r'*censored*'

# ? supported Audio types

audio_extensions = [".m4a", ".flac", "mp3", ".wav", ".wma", ".aac"]

def make_unique(dest, name):
filename, extension = splitext(name)
counter = 1
# * IF FILE EXISTS, ADDS NUMBER TO THE END OF THE FILENAME
while exists(f"{dest}/{name}"):
name = f"{filename}({str(counter)}){extension}"
counter += 1

    return name

def move_file(dest, entry, name):
if exists(f"{dest}/{name}"):
unique_name = make_unique(dest, name)
oldName = join(dest, name)
newName = join(dest, unique_name)
rename(oldName, newName)
move(entry, dest)

class MoverHandler(FileSystemEventHandler):
# ? THIS FUNCTION WILL RUN WHENEVER THERE IS A CHANGE IN "source_dir"
# ? .upper is for not missing out on files with uppercase extensions
def on_modified(self, event):
with scandir(source_dir) as entries:
for entry in entries:
name = entry.name
self.check_audio_files(entry, name)

    def check_audio_files(self, entry, name):  # * Checks all Audio Files
        for audio_extension in audio_extensions:
            if name.endswith(audio_extension) or name.endswith(audio_extension.upper()):
                dest = mp3_dir
                move_file(dest, entry, name)
                logging.info(f"Moved audio file: {name}")

if __name__ == "__main__":
logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
path = source_dir
event_handler = MoverHandler()
observer = Observer()
observer.schedule(event_handler, path, recursive=True)
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()

问题原因

核心问题出在move_file函数里的move(entry, dest)这一行:shutil.move()要求第一个参数是文件路径的字符串,但你传的是scandir返回的DirEntry对象。shutil.move内部会对路径做字符串处理(比如调用rstrip),而DirEntry是个对象,没有这些字符串方法,所以触发了错误。

另外原代码存在缩进问题(Python对缩进严格),部分代码块缩进不正确,也会导致运行异常。


修复后的完整代码

from os import scandir, rename
from os.path import splitext, exists, join
from shutil import move
import time
import logging

from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

source_dir=r'*censored*'
mp3_dir=r'*censored*'

# 支持的音频格式
audio_extensions = [".m4a", ".flac", ".mp3", ".wav", ".wma", ".aac"]

def make_unique(dest, name):
    filename, extension = splitext(name)
    counter = 1
    # 如果文件已存在,给文件名加数字后缀
    while exists(f"{dest}/{name}"):
        name = f"{filename}({str(counter)}){extension}"
        counter += 1
    return name

def move_file(dest, entry, name):
    if exists(f"{dest}/{name}"):
        unique_name = make_unique(dest, name)
        oldName = join(dest, name)
        newName = join(dest, unique_name)
        rename(oldName, newName)
    # 核心修复:传入文件路径字符串而非DirEntry对象,同时指定完整目标路径
    move(entry.path, join(dest, name))

class MoverHandler(FileSystemEventHandler):
    # 当source_dir有变化时触发
    # .upper是为了不遗漏大写扩展名的文件
    def on_modified(self, event):
        with scandir(source_dir) as entries:
            for entry in entries:
                # 跳过目录,只处理文件
                if entry.is_file():
                    name = entry.name
                    self.check_audio_files(entry, name)

    def check_audio_files(self, entry, name):  # 检查所有音频文件
        for audio_extension in audio_extensions:
            if name.endswith(audio_extension) or name.endswith(audio_extension.upper()):
                dest = mp3_dir
                move_file(dest, entry, name)
                logging.info(f"Moved audio file: {name}")

if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO,
                        format='%(asctime)s - %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S')
    path = source_dir
    event_handler = MoverHandler()
    observer = Observer()
    observer.schedule(event_handler, path, recursive=True)
    observer.start()
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
        observer.join()

关键修改点

  1. 核心错误修复:将move(entry, dest)改为move(entry.path, join(dest, name)),entry.path是文件的完整路径字符串,符合shutil.move的参数要求;同时指定目标路径的完整文件名,避免移动后文件名异常。
  2. 缩进修正:修复了make_unique、move_file函数内部的缩进问题,确保Python能正确识别代码块。
  3. 添加目录过滤:在on_modified里增加if entry.is_file()判断,避免尝试移动目录导致的额外错误。
  4. 扩展名修正:把原列表里的"mp3"改成".mp3",保证扩展名匹配逻辑正确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 00:35:36