Welcome, guest | Sign In | My Account | Store | Cart

Provides disk usage statistics (total, used and free disk space) about a given path.

This recipe was initially developed for psutil:

...and then included into shutil module starting from Python 3.3:

The recipe you see here is a modified version of the latter one in that the Windows implementation uses ctypes instead of a C extension module. As such it can be used with python >= 2.5.

Python, 45 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/usr/bin/env python

"""
Return disk usage statistics about the given path as a (total, used, free)
namedtuple.  Values are expressed in bytes.
"""
# Author: Giampaolo Rodola' <g.rodola [AT] gmail [DOT] com>
# License: MIT

import os
import collections

_ntuple_diskusage = collections.namedtuple('usage', 'total used free')

if hasattr(os, 'statvfs'):  # POSIX
    def disk_usage(path):
        st = os.statvfs(path)
        free = st.f_bavail * st.f_frsize
        total = st.f_blocks * st.f_frsize
        used = (st.f_blocks - st.f_bfree) * st.f_frsize
        return _ntuple_diskusage(total, used, free)

elif os.name == 'nt':       # Windows
    import ctypes
    import sys

    def disk_usage(path):
        _, total, free = ctypes.c_ulonglong(), ctypes.c_ulonglong(), \
                           ctypes.c_ulonglong()
        if sys.version_info >= (3,) or isinstance(path, unicode):
            fun = ctypes.windll.kernel32.GetDiskFreeSpaceExW
        else:
            fun = ctypes.windll.kernel32.GetDiskFreeSpaceExA
        ret = fun(path, ctypes.byref(_), ctypes.byref(total), ctypes.byref(free))
        if ret == 0:
            raise ctypes.WinError()
        used = total.value - free.value
        return _ntuple_diskusage(total.value, used, free.value)
else:
    raise NotImplementedError("platform not supported")

disk_usage.__doc__ = __doc__

if __name__ == '__main__':
    print disk_usage(os.getcwd())

Posix

>>> disk_usage('/')
usage(total=21378641920, used=9479311360, free=10813341696)
>>> disk_usage('/home')
usage(total=30227386368, used=17368702976, free=11323203584)
>>>

Windows

>>> disk_usage('C:\\')
usage(total=4188008448L, used=2574508032L, free=1613500416L)
>>> disk_usage(u'C:\\')
usage(total=4188008448L, used=2574508032L, free=1613500416L)
>>>

Print results in a human readable form

def bytes2human(n):
    symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
    prefix = {}
    for i, s in enumerate(symbols):
        prefix[s] = 1 << (i+1)*10
    for s in reversed(symbols):
        if n >= prefix[s]:
            value = float(n) / prefix[s]
            return '%.1f%s' % (value, s)
    return "%sB" % n

>>> usage = disk_usage('/')
>>> usage.total
21378641920
>>> bytes2human(usage.total)
'19.9G'

5 comments

Rogier Steehouder 12 years, 5 months ago  # | flag

In Python 3, use GetDiskFreeSpaceExW (Unicode strings).

Giampaolo Rodolà (author) 12 years, 5 months ago  # | flag

Fixed, thanks.

siggi2017 11 years, 7 months ago  # | flag

that was what i was looking for. but the parameters of GetDiskFreeSpaceEx are ULARGE_INTEGER. so in line 28 ctypes.c_ulonglong() would be appropriate. at least it works like this for me with some drives larger than 4.3GByte

Giampaolo Rodolà (author) 11 years, 7 months ago  # | flag

Fixed.

_ 8 years, 10 months ago  # | flag

Hi Gia. Hope all is well. The first script, i implemented it using python 3.4.2 But how does one break the Bytes into Gigabytes?