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

Have you ever been annoyed with the names digital cameras give to their pictures? After considering the problem and wanting to standardize filenames, the following program was written to give files in their respective directories similar names according to a convention. For those who may be just starting out with programming and have a similar objective, this recipe may help show some of what may be involved in the process.

Python, 89 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
import os
import sys

# NOTE
# ====
# Renaming should happen in groups based on extention.
# All files should first be renamed with a unique ID.

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

ERR = False
ALL = ''.join(map(chr, xrange(256)))
NUM = '0123456789'
LET = ALL.translate(ALL, NUM)
EXT = 'avi', 'bmp', 'gif', 'jpg', 'wmv'

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

class Filename:

    def __init__(self, filename):
        self.filename = filename.lower()
        split = self.filename.rsplit('.', 1)
        self.name = split[0]
        self.ext = split[1] if len(split) == 2 else ''
        self.let = self.name.translate(ALL, NUM)
        self.num = self.name.translate(ALL, LET)

    def __eq__(self, other):
        return bool(self.num) and other == int(self.num)

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

def main():
    try:
        arguments = sys.argv[1:]
        assert arguments
        for path in arguments:
            assert os.path.isdir(path)
        for path in arguments:
            engine(path)
    except:
        sys.stdout.write('Usage: %s <directory>' % os.path.basename(sys.argv[0]))

def engine(path):
    global ERR
    for root, dirs, files in os.walk(path):
        # gather all relevant names
        files = filter(lambda name: name.num and name.ext in EXT, map(Filename, files))
        # find all taken number names
        taken = []
        for name in files[:]:
            if name.name == name.num:
                files.remove(name)
                taken.append(name)
        # put all names in order
        files.sort(compare)
        taken.sort(compare)
        # rename all non-number names
        count = 0
        for name in files:
            while count in taken:
                taken.remove(count)
                count += 1
            name.new = str(count)
            count += 1
        # condense all numerical names
        for name in taken:
            if name.num != str(count):
                name.new = str(count)
                files.append(name)
            count += 1
        # rename files needing new names
        for name in files:
            old = os.path.join(root, name.filename)
            try:
                os.rename(old, os.path.join(root, name.new + '.' + name.ext))
            except:
                sys.stderr.write('%sError: %s' % (ERR and '\n' or '', old))
                ERR = True

def compare(x, y):
    integer = cmp(x.let, y.let)
    return integer if integer else cmp(int(x.num), int(y.num))

################################################################################
    
if __name__ == '__main__':
    main()