在我重新发明这个特殊的轮子之前,有没有人有一个很好的用Python计算目录大小的例程?如果该例程能以Mb/Gb等格式格式化大小,那就太好了。


当前回答

你说一句俏皮话… 这里有一句话:

sum([sum(map(lambda fname: os.path.getsize(os.path.join(directory, fname)), files)) for directory, folders, files in os.walk(path)])

尽管我可能会把它分开,它不执行检查。

要转换为kb,请参阅可重用库以获得人类可读版本的文件大小?然后算进去

其他回答

不管怎样……树命令免费完成所有这些工作:

tree -h --du /path/to/dir  # files and dirs
tree -h -d --du /path/to/dir  # dirs only

我喜欢Python,但到目前为止,这个问题最简单的解决方案不需要新的代码。

使用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)

我还遇到了这个问题,它有一些更紧凑、可能更高效的打印文件大小的策略。

你可以这样做:

import commands   
size = commands.getoutput('du -sh /path/').split()[0]

在这种情况下,我没有在返回之前测试结果,如果你想要,你可以用commands.getstatusoutput检查它。

当计算子目录的大小时,它应该更新其父目录的文件夹大小,这将一直进行下去,直到它到达根父目录。

下面的函数计算文件夹及其所有子文件夹的大小。

import os

def folder_size(path):
    parent = {}  # path to parent path mapper
    folder_size = {}  # storing the size of directories
    folder = os.path.realpath(path)

    for root, _, filenames in os.walk(folder):
        if root == folder:
            parent[root] = -1  # the root folder will not have any parent
            folder_size[root] = 0.0  # intializing the size to 0

        elif root not in parent:
            immediate_parent_path = os.path.dirname(root)  # extract the immediate parent of the subdirectory
            parent[root] = immediate_parent_path  # store the parent of the subdirectory
            folder_size[root] = 0.0  # initialize the size to 0

        total_size = 0
        for filename in filenames:
            filepath = os.path.join(root, filename)
            total_size += os.stat(filepath).st_size  # computing the size of the files under the directory
        folder_size[root] = total_size  # store the updated size

        temp_path = root  # for subdirectories, we need to update the size of the parent till the root parent
        while parent[temp_path] != -1:
            folder_size[parent[temp_path]] += total_size
            temp_path = parent[temp_path]

    return folder_size[folder]/1000000.0

这将遍历所有子目录;文件大小总和:

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')

和一个在线的乐趣使用操作系统。listdir(不包括子目录):

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

参考:

os.path.getsize -以字节为单位给出大小 os.walk os.path.islink

更新 使用os.path。Getsize,这比使用os.stat()更清楚。st_size方法。

感谢ghostdog74指出这一点!

操作系统。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及以后版本中,此包已合并到标准库和操作系统中。行走得到了相应的性能提升。

更新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())