目录大小和扩展名

3
我想创建Python命令行代码,能够打印指定目录下所有子目录的大小及其最常见的扩展名... 以下是输出示例。
  • 根目录 (5 GB, jpg (65 %): avi ( 30 %) : pdf (5 %))

-- aa (3 GB, jpg (100 %) )

-- bb (2 GB, avi (20 %) : pdf (2 %) )

--- bbb (1 GB, ...)

--- bb2 (1 GB, ...)

-- cc (1 GB, pdf (100 %) )

格式如下:
嵌套级别、目录名称(包含所有文件和子目录的大小)以及该目录中最常见的扩展名及其大小百分比。
我目前有这段代码片段。问题在于它只计算目录中的文件大小,因此结果大小小于目录的实际大小。另一个问题是如何将所有内容组合在一起,以便按照上面定义的树形结构进行打印,而不产生冗余计算。

你写过任何代码或者规划了逻辑吗?请发表。 - foosion
4个回答

4

计算目录大小并不是Python的强项,如此帖子所述:非常快速地获取文件夹的总大小。如果您可以访问dufind,那么请务必使用它们。您可以使用以下行轻松显示每个目录的大小:

find . -type d -exec du -hs "{}" \;

如果你坚持使用Python完成此任务,你可能会更喜欢PableG建议的后序遍历而不是os.walk。但是,如果效率不是最重要的因素,使用os.walk可以使代码更加清晰易懂。请参考这里进行学习。
import os, sys
from collections import defaultdict

def walkIt(folder):
    for (path, dirs, files) in os.walk(folder):
        size = getDirSize(path)
        stats = getExtensionStats(files)

        # only get the top 3 extensions
        print '%s (%s, %s)'%(path, size, stats[:3])

def getExtensionStats(files):
    # get all file extensions
    extensions = [f.rsplit(os.extsep, 1)[-1] 
        for f in files if len(f.rsplit(os.extsep, 1)) > 1]

    # count the extensions
    exCounter = defaultdict(int)
    for e in extensions:
        exCounter[e] += 1

    # convert count to percentage
    percentPairs = [(e, 100*ct/len(extensions)) for e, ct in exCounter.items()]

    # sort them
    percentPairs.sort(key=lambda i: i[1])
    return percentPairs

def getDirSize(root):
    size = 0
    for path, dirs, files in os.walk(root):
        for f in files:
            size +=  os.path.getsize( os.path.join( path, f ) )
    return size

if __name__ == '__main__':
    path = sys.argv[1] if len(sys.argv) > 1 else '.'
    walkIt(path)

2

我个人认为,对于这个任务,os.listdir + 递归函数比os.walk更合适:

import os, copy
from os.path import join, getsize, isdir, splitext

frequent_ext = { ".jpg": 0, ".pdf": 0 }     # Frequent extensions

def list_dir(base_dir):
    dir_sz = 0  # directory size
    files = os.listdir(base_dir)
    ext_size = copy.copy(frequent_ext)

    for file_ in files:
        file_ = join(base_dir, file_)

        if isdir(file_):
            ret = list_dir(file_)
            dir_sz += ret[0]
            for k, v in frequent_ext.items():           # Add to freq.ext.sizes
                ext_size[k] += ret[1][k]
        else:
            file_sz = getsize(file_)
            dir_sz += file_sz

            ext = os.path.splitext(file_)[1].lower()   # Frequent extension?
            if ext in frequent_ext.keys():
                ext_size[ext] += file_sz

    print base_dir, dir_sz,
    for k, v in ext_size.items():
        print "%s: %5.2f%%" % (k, float(v) / max(1, dir_sz) * 100.),

    print 

    return (dir_sz, ext_size)


base_dir = "e:/test_dir/"
base_dir = os.path.abspath(base_dir)
list_dir(base_dir)

谢谢,你的代码教会了我Python中很好的东西。我尝试使用os.walk,但它的用法相当复杂。你的递归看起来非常优雅。我正在尝试测试它,但是它给我错误 - xralf
我注意到它崩溃的目录是符号链接。如果可能的话,应该避免使用符号链接。我现在正在Linux(Ubuntu)上进行测试,但主要用途将在Windows 7上。 - xralf

0

@Cldy 是对的,使用 os.path

例如,os.path.walk 将深度优先遍历参数下面的每个目录,并返回每个目录中的文件和文件夹

使用 os.path.getsize 获取大小并拆分以获取扩展名。将扩展名存储在列表或字典中,在每次遍历后计数

如果您使用的是 Linux,则建议查看 du


-2

这些将是最有用的模块。+1。也许加入一个字典来跟踪扩展名和大小。 - foosion
3
如果你只想引导某人使用一个模块,而不对它进行其他解释,请使用注释。如果你打算回答问题,至少指出具体的函数或给他们提供一个想法来解决问题。(我不是那个点踩的人,我今天的投票用完了,但我同意这个观点)。 - agf
我指出这些模块是因为我认为它们足够好且文档已经很清楚了。也许你说的对,这应该更适合作为一个注释。然而文档已经说明了一切,所以我不会改变我的答案。 - Mariy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接