使用Python计算目录大小?

291 投票
34 回答
305788 浏览
提问于 2025-04-15 14:08

在我重新发明这个轮子之前,有没有人能分享一个用Python计算文件夹大小的好方法?如果这个方法能把大小格式化得好看一点,比如用Mb或Gb来显示,那就更好了。

34 个回答

33

我用 pathlib 写了一个一行代码,可以用来获取文件夹的大小:

sum(file.stat().st_size for file in Path(folder).rglob('*'))

这是我为输出结果格式化而写的代码:

from pathlib import Path


def get_folder_size(folder):
    return ByteSize(sum(file.stat().st_size for file in Path(folder).rglob('*')))


class ByteSize(int):

    _KB = 1024
    _suffixes = 'B', 'KB', 'MB', 'GB', 'PB'

    def __new__(cls, *args, **kwargs):
        return super().__new__(cls, *args, **kwargs)

    def __init__(self, *args, **kwargs):
        self.bytes = self.B = int(self)
        self.kilobytes = self.KB = self / self._KB**1
        self.megabytes = self.MB = self / self._KB**2
        self.gigabytes = self.GB = self / self._KB**3
        self.petabytes = self.PB = self / self._KB**4
        *suffixes, last = self._suffixes
        suffix = next((
            suffix
            for suffix in suffixes
            if 1 < getattr(self, suffix) < self._KB
        ), last)
        self.readable = suffix, getattr(self, suffix)

        super().__init__()

    def __str__(self):
        return self.__format__('.2f')

    def __repr__(self):
        return '{}({})'.format(self.__class__.__name__, super().__repr__())

    def __format__(self, format_spec):
        suffix, val = self.readable
        return '{val:{fmt}} {suf}'.format(val=val, fmt=format_spec, suf=suffix)

    def __sub__(self, other):
        return self.__class__(super().__sub__(other))

    def __add__(self, other):
        return self.__class__(super().__add__(other))
    
    def __mul__(self, other):
        return self.__class__(super().__mul__(other))

    def __rsub__(self, other):
        return self.__class__(super().__sub__(other))

    def __radd__(self, other):
        return self.__class__(super().__add__(other))
    
    def __rmul__(self, other):
        return self.__class__(super().__rmul__(other))   

使用方法:

>>> size = get_folder_size("c:/users/tdavis/downloads")
>>> print(size)
5.81 GB
>>> size.GB
5.810891855508089
>>> size.gigabytes
5.810891855508089
>>> size.PB
0.005674699077644618
>>> size.MB
5950.353260040283
>>> size
ByteSize(6239397620)

我还看到这个 问题,里面有一些更简洁、可能更高效的打印文件大小的方法。

70

到目前为止,有些方法使用了递归,有些则用了一些外部工具,结果可能也不太整齐。如果你的代码只是为了在Linux平台上用一次,那么你可以像往常一样得到格式化的结果,包括递归,这一切都可以用一行代码实现。除了最后一行的print,这段代码在当前版本的python2python3中都能运行:

du.py
-----
#!/usr/bin/python3
import subprocess

def du(path):
    """disk usage in human readable format (e.g. '2,1GB')"""
    return subprocess.check_output(['du','-sh', path]).split()[0].decode('utf-8')

if __name__ == "__main__":
    print(du('.'))

这段代码简单高效,适用于文件和多层目录:

$ chmod 750 du.py
$ ./du.py
2,9M
401

这段代码会遍历所有子目录,并计算文件的大小:

import os

def get_size(start_path = '.'):
    total_size = 0
    for dirpath, dirnames, filenames in os.walk(start_path):
        for f in filenames:
            fp = os.path.join(dirpath, f)
            # skip if it is symbolic link
            if not os.path.islink(fp):
                total_size += os.path.getsize(fp)

    return total_size

print(get_size(), 'bytes')

还有一个有趣的单行代码,使用了 os.listdir不包括子目录):

import os
sum(os.path.getsize(f) for f in os.listdir('.') if os.path.isfile(f))

参考资料:

更新

使用 os.path.getsize 这个方法比用 os.stat().st_size 方法更清晰。

感谢 ghostdog74 提醒这一点!

os.stat - st_size 返回文件大小(以字节为单位)。也可以用来获取文件大小和其他与文件相关的信息。

import os

nbytes = sum(d.stat().st_size for d in os.scandir('.') if d.is_file())

2018年更新

如果你使用的是 Python 3.4 或更早版本,可以考虑使用第三方的 scandir 包提供的更高效的 walk 方法。在 Python 3.5 及以后的版本中,这个包已经被整合进标准库,os.walk 的性能也得到了相应的提升。

2019年更新

最近我越来越多地使用 pathlib,这里有一个 pathlib 的解决方案:

from pathlib import Path

root_directory = Path('.')
sum(f.stat().st_size for f in root_directory.glob('**/*') if f.is_file())

撰写回答