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

Walk through a list of directories and rename the files within those directories based on the directory name and an index value. Useful for managing photos when downloaded from a camera into directories based on the shooting date.

Python, 124 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
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#
#   Dir Walking File Renamer
#   by Mickey Hadick
#   Created: December 27, 2008
#   Copyright (C) 2008 Mickey Hadick
#   Free to copy, correct, and use at your discretion.
#   Inspired by several recipes, especially:
#   http://code.activestate.com/recipes/105873/
#
#   This module reads a file that contains a list of directory names.
#   It visits each directory in that file, and renames the files found
#   in those directories.
#   The base path is the path where the file was found.
#   The files are renamed based the directory name, with some unique
#   identifier added onto the end of that name.
#
#   I use this for the photos I download from my camera. I rename the
#   directory to reflect the subject (creating new directories if
#   necessary--like when I take multiple photos on a particular day)
#   and then let all the photos take that name.  The date of the photo
#   is part of the directory name (a setting from the camera software)
#   and then I upload everything to Fotki (in general, not in this
#   module) and all the photos have the date and the subject in their
#   file name.
#

import os, sys, optparse

class NoFile(Exception):
    def __init__(self,msg):
        self.msg = msg


def renameFilesInDir( dir_name ):
    """
    given a directory
    rename all the files therein with the pattern:
    dir_name_nnnn
    where nnnn is a unique number (just count up from 1)
    NOTE: the file extension is preserved!
    NOTE: it does not recurse through sub directories!!
    """
    i = 1   # index used to create unique name in directory

    print 'dir_name is: ', dir_name

    for f in os.listdir( dir_name):

        print 'file: ', f, '--',
        
        if os.path.isdir(f):
            print 'skipping'
            continue

        # if, for example, dir_name is: "d:\pictures\2008\2008_11_01_family"
        # f, at this point, is d:\pictures\2008\2008_11_01_family\img0001.jpg
        # dir_basename needs to be 2008_11_01_family
        # then we rename f to be 2008_11_01_family_0001.jpg (in that same dir)

        froot, ext = os.path.splitext(f)        #get the extension
        # (froot is d:\pictures\2008\2008_11_01_family\img0001)
        # (ext is jpg)

        if ext.lower() != '.jpg':
            print 'skipping'
            continue                # we only work on JPEGs

        dir_root, fname = os.path.split(froot)  #get the dir and base names
        # (dir_root is d:\pictures\2008\2008_11_01_family)
        # (fname is img0001)

        dir_basename = os.path.basename( dir_name)
        # (dir_basename is 2008_11_01_family) <= that's the one I really want!

        new_base = dir_basename + str.format('{i:04}',i=i) + ext
        new_name = os.path.join(dir_name, new_base)
        # uses the new string formatting, to generate the "0001" numbering

        file_to_rename = os.path.join(dir_name, f)

        print 'Renaming %s to %s.' % (f,new_base)
        os.rename(file_to_rename, new_name)
        
        i += 1      # 1 becomes 2, etc.

        # that should do it.


def myMain( file_of_dirs ):
    """
    reads the file (name passed)
    visits each dir
    renames the files therein
    """
    try:
        #test whether the file passed exists, and the path is good
        if not os.path.exists( file_of_dirs ):
            raise NoFile("File does not exist")
        dname, fod_name = os.path.split (file_of_dirs )

        with open( file_of_dirs, 'r') as f:
            for fname in f:
                fname = fname.rstrip('\n')
                dir_to_walk = os.path.join(dname, fname)
                if not os.path.exists( dir_to_walk ):
                    print "Directory %s does not exist--can't process" % dir_to_walk
                else:
                    renameFilesInDir( dir_to_walk )
    except NoFile, err:
        print err.msg
    except:
       exc_info = sys.exc_info()
       print "unhandled exception in DirWalkRenameFile: %s %s %s" % (exc_info[0],exc_info[1],exc_info[2])

if __name__ == '__main__':

    parser=optparse.OptionParser()
    parser.add_option('-f','--filename',dest='input_filename',
                type="string",
                default="d:/pictures/2008test/nov_files.txt",
                help="Filename of file with directories to rename.")
    (options, args) = parser.parse_args()
    
    myMain( options.input_filename )
    

This is mostly directed at Windows platforms, to rename photos downloaded from cameras.

This recipe requires a text file populated with the directory names that you wish to walk in order to rename the files within those directories. Consider the following:

d:\pictures\2008\2008_01_01_Party d:\pictures\2008\2008_03_15_StPats

In those directories you have numerous embarrassing photos you want to upload, but you don't want the names to be 268_001.jpg, 268_002.jpg; instead, you want them to be 2008_01_01_Party0001.jpg, etc., so that you have a small reminder.

In the d:\pictures\2008 directory, create a file of all the directories whose photos you want to rename (e.g., twodirs.txt) and in that file put just the directory names:

twodirs.txt: 2008_01_01_Party 2008_03_15_StPats

The easy way to do this is use "DIR /B > twodirs.txt" from the command line. Edit that file as you see fit, and pass it as a parameter to this recipe.

This recipe only renames ".JPG" files, and skips the rest. Neither does it recurse subdirectories.

Possible improvements include passing the extension to skip as a parameter, and reading the list of files from standard input.

NOTE: mind the separators for the full path--they're a pain.