pee2pee
pee2pee

Reputation: 3792

Python - Move files to folders which contain part of the filename

I've tried several iterations of a script but now back to staring at a blank Notepad++

I have 6k folders in the form:

Reading Festival 1999
Reading Festival 2000
Reading Festival 2001
Leeds Festival 1999
Leeds Festival 2000
Leeds Festival 2001
Download Festival 2005
Download Festival 2006
...

In the same folder I have a long list of files in the form

Artist at {Festival Name} by Photographer - UID

Where Artist is someone who played at the festival, Photographer is the person who took it and UID is a unique ID

My question is how would I go about looping through the folders, for each, see if a filename contains the name of the folder, if it does, move the file there.

import os
rootdir = 'C:\Users\Alan\Desktop\VF'

for subdir, dirs, files in os.walk(rootdir):
    for d in dirs:
        for file in files:
            the_file = os.path.join(subdir, file)
            if d in the_file:
                new_loc = subdir + '\\' + d + '\\' + file
                os.rename(the_file, new_loc)

I have this code which I believe should work but my worry is that it will read through all the images already within folders. How would I avoid this?

Upvotes: 2

Views: 1303

Answers (2)

s.py
s.py

Reputation: 197

Since your files and folders are on the same level, you don't need to use os.walk() to traverse the directory tree. os.listdir() will do instead, as you noted in the comments. One solution would be to get the directory and file lists with os.listdir() and find the new_loc name in the same way you did before, using in instead of regex.

folders = [d for d in os.listdir('.') if os.path.isdir(d)]
files = [f for f in os.listdir('.') if os.path.isfile(f)]
for d in folders:
   for f in files:
      if d in f:
          new_loc = subdir + '\\' + d + '\\' + file
          os.rename(the_file, new_loc)

The logic here is about the same as yours, just with a different way of getting your directories and files!

Upvotes: 1

hoyland
hoyland

Reputation: 1824

If I'm understanding properly, you have a top level directory and when you start this process, everything in it is either an empty directory corresponding to a festival or a file to be moved. I don't think you need to use os.walk at all, just iterate through what's in the top level directory.

I'll assume you have two functions defined:

  • def extract_festival(fname) returning "Reading Festival 1999" or whatever is appropriate
  • def move_file(fname, festival) to move the file into place. You'll need to check whether the festival's directory exists and if not do whatever's appropriate.

Then you just need something like:

for fname in os.listdir(rootdir):
    if os.path.isfile(os.path.join(rootdir, fname)): # double check that listdir doesn't give you the full path
        festival = extract_festival(fname)
        move_file(fname, festival)
    # otherwise, it's a directory, so leave it alone

I do think that extract_festival is a regex. Something like this will handle the "happy" case:

def extract_festival(fname):
    match = re.match(".+at(.+[0-9]{4}) by.+")
    return match.group(1)

If you fail to match (e.g. if you have a bad file name), match will be None and you'll have to decide what to do. The match.group will throw an error in that case. I'd probably do something like return match.group(1) if match is not None else match and then check for None up in the for loop (and probably print the filename so I could go fix it by hand).

Upvotes: 0

Related Questions