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

Have you ever wanted to find out how much room a particular directory was taking up on your hard drive? A roommate of mine in college was having trouble keeping track of where his hard drive space is going, so the following program provided a solution that allows a brief overview of a directory's size along with all of its children. A tree view is printed out in ASCII characters showing the relationship of each directory along with its size in a format easily readable to humans. The output can always be redirected to a text file if it needs to be saved for viewing later on.

Python, 94 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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import os, sys

################################################################################

def main():
    try:
        tree = SizeTree(os.path.abspath(sys.argv[1]))
    except IndexError:
        print('Usage: {} <directory>'.format(os.path.basename(sys.argv[0])))
    else:
        show(tree)

def show(tree):
    print('{} [{}]'.format(tree.path, convert(tree.total_size)))
    walk(tree, '')
    if not tree.children:
        print('No subfolders exist')

def walk(tree, prefix):
    dir_prefix, walk_prefix = prefix + '+---', prefix + '|   '
    for pos, neg, child in enumerate2(tree.children):
        if neg == -1:
            dir_prefix, walk_prefix = prefix + '\\---', prefix + '    '
        print('{}{} [{}]'.format(dir_prefix, child.name,
                                 convert(child.total_size)))
        walk(child, walk_prefix)

def enumerate2(sequence):
    length = len(sequence)
    for count, value in enumerate(sequence):
        yield count, count - length, value

################################################################################

class SizeTree:

    def __init__(self, path, name=None):
        self.path = path
        self.name = os.path.basename(path) if name is None else name
        self.children = []
        self.file_size = 0
        self.total_size = 0
        try:
            dir_list = os.listdir(path)
        except OSError:
            pass
        else:
            for name in dir_list:
                path_name = os.path.join(path, name)
                if os.path.isdir(path_name):
                    size_tree = SizeTree(path_name, name)
                    self.children.append(size_tree)
                    self.total_size += size_tree.total_size
                elif os.path.isfile(path_name):
                    try:
                        self.file_size += os.path.getsize(path_name)
                    except OSError:
                        pass
        self.total_size += self.file_size

################################################################################

def convert(number):
    "Convert bytes into human-readable representation."
    if not number:
        return '0 Bytes'
    assert 0 < number < 1 << 110, 'number out of range'
    ordered = reversed(tuple(format_bytes(partition_number(number, 1 << 10))))
    cleaned = ', '.join(item for item in ordered if item[0] != '0')
    return cleaned

def partition_number(number, base):
    "Continually divide number by base until zero."
    div, mod = divmod(number, base)
    yield mod
    while div:
        div, mod = divmod(div, base)
        yield mod

def format_bytes(parts):
    "Format partitioned bytes into human-readable strings."
    for power, number in enumerate(parts):
        yield '{} {}'.format(number, format_suffix(power, number))

def format_suffix(power, number):
    "Compute the suffix for a certain power of bytes."
    return (PREFIX[power] + 'byte').capitalize() + ('s' if number != 1 else '')

PREFIX = ' kilo mega giga tera peta exa zetta yotta bronto geop'.split(' ')

################################################################################

if __name__ == '__main__':
    main()

This simple utility was re-envisioned with a GUI that has been substantially enhanced and is available as recipe 577567.

1 comment

Marco 13 years, 2 months ago  # | flag

For python 2.6 you will have to rewrite the print commands(e.g.: line: 14 print('{} [{}]'.format(tree.path, convert(tree.total_size))) to print('{0} [{1}]'.format(tree.path, convert(tree.total_size))))

Otherwise python would not know where to put the arguments.

Since I cannot copy the entire program as a comment(max. 3000 chars.), I will put the affected lines here:

line 9:print('Usage: {0} <directory>'.format(os.path.basename(sys.argv[0])))
line 14:print('{0} [{1}]'.format(tree.path, convert(tree.total_size)))
line 24:print('{0}{1} [{2}]'.format(dir_prefix, child.name, convert(child.total_size)))
line 83:yield '{0} {1}'.format(number, format_suffix(power, number))