“Disarming” code that could wreck your harddrive

(Original post from 16. Dec 2011)

Here I am back in the land of the python πŸ˜‰ I’ve had another one of those downtimes that probably only hobby programmers suffer from when the real world took over and didn’t allow for any time to do the fun stuff.

I had an interestingly simple problem yesterday (yes, I only write about it today, because reality still gives me a regular nudge), that revolved about 2 DVDs with a grand total of about 400 pictures. I wanted to put them all in the same folder, but unfortunately the person who developed them and put them on DVDs used the same naming scheme for both of them, which meant that if I wanted to put them in the same folder by copy paste, I would have overwritten the first half of pictures.

As a solution I did not turn to IrfanView like any sane person with a little bit of computer literacy would have done, instead I decided to write my own python renaming script. I started off with the following:

import os  

def change_all_filenames(directory, new_name, suffix):  
    i = 0 

    for root, dirs, files in os.walk(directory): 
        for f in files: 
            os.renames(os.path.join(root,f), 
                       os.path.join(root,new_name))  
        i += 1

This script works. It works very well even, but it has a certain problem associated with it. It doesn’t distinguish between files and as such this could have huuuuge implications. Just imagine you pass 'c:/' in Windows or '/home' as the starting directory. You would, in fact, rename every single file on your harddrive to new_name and if you don’t give a file ending, you would also render them all invalid, effectively wrecking your OS installation.

It just goes to show, that a very simple script meant for one thing can have a very large effect on something entirely different. So as an exercise, I decided to put a couple of fail safes in, just to make this a little bit more safe to use.

The first thing to do is, to give an optional suffix in so that you only change files of the same type. Still not exactly safe, but much better. If you only change jpgs now, this most likely won’t destroy many important files. To do this, all I had to do was use a couple of string operations.

import os  

def change_all_filenames(directory, new_name, suffix):  
    i = 0 

    for root, dirs, files in os.walk(directory): 
        for f in files: 
            spl = f.split(".") 
            if spl[-1] == suffix.upper() or \
               spl[-1] == suffix.lower(): 
                os.renames(os.path.join(root,f), 
                           os.path.join(root, 
                           "{0}{1}.{2}".format(new_name, i,
                           spl[-1])))  
        i += 1

The last thing, I did to round this off, is to give the option of a “dry run”, by only giving the printed output of what would be changed when run for real.

import os  

def change_all_filenames(directory, new_name, suffix, print_only=False):  
    i = 0 

    for root, dirs, files in os.walk(directory): 
        for f in files: 
            spl = f.split(".") 
            if spl[-1] == suffix.upper() or \
               spl[-1] == suffix.lower(): 
                if print_only:
                    print os.path.join(root, 
                          "{0}{1}.{2}".format(new_name, 
                          i, spl[-1]))
                else:
                    os.renames(os.path.join(root,f), 
                               os.path.join(root, 
                               "{0}{1}.{2}".format(new_name, i,
                               spl[-1])))  
        i += 1

I left it at this point, but there are still things that can be done, to make it more user-friendly. For example, using sys.argv to be able to pass arguments from the command line or even put a GUI in place to use it.

Safety-wise, there are still a couple of things that can be done, like disallowing certain locations on different platforms (e.g. the WINDOWS folder), but that was too much hassle for my little file renaming problem.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s