os.walk() 两次访问同一个文件夹

os.walk() visits same folder twice

我正在使用 mutagen library 编写简单的脚本,它计算文件夹中的音频文件数量和文件夹的整个音频播放时间(包括子文件夹中的音频文件)。

import os,sys
from datetime import datetime,timedelta
from mutagen.mp3 import MP3
from mutagen.flac import FLAC
from mutagen.aac import AAC
from mutagen.aiff import AIFF
from mutagen.asf import ASF

audio_ext={"mp3":lambda x: MP3(x).info.length,
           "aac":lambda x: AAC(x).info.length,
           "wmv":lambda x: ASF(x).info.length,
           "wma":lambda x: ASF(x).info.length,
           "asf":lambda x: ASF(x).info.length,
           "flac":lambda x: FLAC(x).info.length,
           "aiff":lambda x: AIFF(x).info.length,}

def scan_lib(path):
    playtime = 0
    audio_files = 0
    for root,dirs,files in os.walk(path,followlinks=False):
        for f in files:
           try:
               playtime += audio_ext[f[len(f)-f[::-1].index('.'):]](os.path.join(root,f))
               audio_files += 1
           except (KeyError,ValueError):
               pass

        for d in dirs:
            dir_playtime,dir_audios = scan_lib(os.path.join(root,d))
            playtime +=dir_playtime
            audio_files += dir_audios

    print("\nLibrary:",path)
    print("Amount of audio files:",audio_files)
    print("Total playing time:\nDays\tHours\tMin\tSec\n%d\t%d\t%d\t%d\n" % convert_pt(playtime))
    return playtime,audio_files

def convert_pt(sec):
    t = datetime(1,1,1) + timedelta(seconds=int(sec))
    return t.day-1, t.hour,t.minute,t.second

main_path = sys.argv[1]
playtime,audio_files = scan_lib(main_path)

经过一些测试,我发现我的脚本访问了一些文件夹两次。通常这些目录是另一个子文件夹中的子文件夹。结果它打印出这样的结果:

$ python3 music_scan.py 

Library: ~/Music/
Amount of audio files: 3520
Total playing time:
Days    Hours   Min Sec
9   7   30  26

但实际上,如果您将所有音轨移动到一个文件夹中,并在该测试文件夹上 运行 脚本,它会显示不同的结果:

$ python3 music_scan.py ~/test
Library: ~/test/
Amount of audio files: 885
Total playing time:
Days    Hours   Min Sec
2   15  49  9

测试文件夹中的音轨数量确实是 885 条。我用 ls | wc -l 命令检查了它 那么为什么 os.walk() 访问某些子文件夹两次?

os.walk 已经递归遍历了整个目录树。

但是,您递归调用了您的方法 scan_lib:

def scan_lib(path):
    ...
    for root,dirs,files in os.walk(path,followlinks=False):
        ...
        for d in dirs:
            dir_playtime,dir_audios = scan_lib(os.path.join(root,d))
            ...

要么使用 os.listdir 而不是 os.walk 并保留递归调用,要么简单地删除以 for d in dirs:.

开头的 4 行