os.path.isfile 不按预期工作

8 投票
4 回答
32369 浏览
提问于 2025-04-17 10:49

我正在尝试扫描我的硬盘,找出jpg和mp3文件。

我写了一个脚本,如果我给它一个包含文件的目录,它能正常工作,但如果我给它根目录,它就什么都不返回。

我刚开始学习Python,所以希望能得到一些帮助。

def findfiles(dirname,fileFilter):

    filesBySize = {}

    def filterfiles(f):
        ext = os.path.splitext(f)[1][1:]
        if ext in fileFilter:
            return True
        else:
            False

    for (path, dirs, fnames) in os.walk(dirname):
        if len(fileFilter)>0:
            fnames = filter(filterfiles,fnames)

        d = os.getcwd()
        os.chdir(dirname)      
        for f in fnames:
            if not os.path.isfile(f) :
                continue

            size = os.stat(f)[stat.ST_SIZE]
            if size < 100:
                continue
            if filesBySize.has_key(size):
                a = filesBySize[size]
            else:
                a = []
                filesBySize[size] = a
            a.append(os.path.join(dirname, f))
          #  print 'File Added: %s' %os.path.join(dirname,f)
            _filecount = _filecount + 1
        os.chdir(d)

    return filesBySize

4 个回答

2

虽然这和你的问题不完全相关,但因为你是Python新手,这里有一些现代Python的小技巧:

os.stat(f)[stat.ST_SIZE]

可以写成

os.stat(f).st_size

而且

if filesBySize.has_key(size):
    a = filesBySize[size]
else:
    a = []
    filesBySize[size] = a

更好的写法是:

a = filesBySize.setdefault(size, [])
3

filesBySize 这个分组方式有点特别。你可以把它放到 findfiles() 函数外面:

#!/usr/bin/env python
import os
import stat
import sys
from collections import defaultdict

def findfiles(rootdir, extensions=None, minsize=100):
    """Find files with given `extensions` and larger than `minsize`.

    If `extensions` is None then don't filter on extensions.
    Yield size, filepath pairs.
    """
    extensions = tuple(extensions) if extensions is not None else extensions
    for path, dirs, files in os.walk(rootdir):
        if extensions is not None: # get files with given extensions
            files = (f for f in files if f.endswith(extensions))
        for f in files:
            f = os.path.join(path, f) 
            try:
                st = os.stat(f)
            except os.error:
                continue # skip
            if stat.S_ISREG(st.st_mode): # isfile
               if st.st_size > minsize:
                  yield st.st_size, f

rootdir = sys.argv[1] # get it from command-line
files_by_size = defaultdict(list)
for size, f in findfiles(rootdir, ['.mp3', '.jpg']):
    files_by_size[size // (1<<20)].append((size, f)) # group in 1M buckets

import pprint
pprint.pprint(dict(files_by_size)) # pretty print

其实不需要使用 os.chdir(),只要调用 os.path.join(path, f) 就可以了。

12

哦,明白了。

你在调用 os.path.isfile(f),这里的 f 是文件名,位于 path 里面。你需要提供一个绝对路径。如果这个调用确实是必要的(它应该总是返回 True)。

试着把你的循环改成这样:

    qualified_filenames = (os.path.join(path, filename) for filename in fnames)
    for f in qualified_filenames:

这样就可以了!

另外,调用 os.chdir() 是不需要的。

还有,正如我在评论中提到的,filterfiles 应该更像这样:

def filterfiles(f):
    ext = os.path.splitext(f)[1][1:]
    return ext in fileFilter

(你漏掉了一个 return)。

撰写回答