tags:

views:

121

answers:

3

Being completely new in python I'm trying to run a command over a set of files in python. The command requires both source and destination file (I'm actually using imagemagick convert as in the example below).

I can supply both source and destination directories, however I can't figure out how to easily retain the directory structure from the source to the destination directory.

E.g. say the srcdir contains the following:

srcdir/
   file1
   file3
   dir1/
       file1
       file2

Then I want the program to create the following destination files on destdir: destdir/file1, destdir/file3, destdir/dir1/file1 and destdir/dir1/file2

So far this is what I came up with:

import os
from subprocess import call

srcdir = os.curdir # just use the current directory
destdir = 'path/to/destination'

for root, dirs, files in os.walk(srcdir):
    for filename in files:
        sourceFile = os.path.join(root, filename)
        destFile = '???'
        cmd = "convert %s -resize 50%% %s" % (sourceFile, destFile)
        call(cmd, shell=True)

The walk method doesn't directly provide what directory the file is under srcdir other than concatenating the root directory string with the file name. Is there some easy way to get the destination file, or do I have to do some string manipulation in order to do this?

A: 

While not pretty, this will preserve the directory structure of the tree:

_, _, subdirs = root.partition(srcdir)
destfile = os.path.join(destdir, subdirs[1:], filename)
SilentGhost
You need to be careful here -- you might end up with a "subdirs" string which begins with '/' or '\', which will make os.path.join treat it as an absolute path, throwing away the destdir part of the expression. If you know what OS you're on, it's fairly easy to work around that, though.
Edward Loper
@Edward: that's why I do slicing, no?
SilentGhost
replace `subdirs[:1]` by `subdirs.lstrip(os.sep)`
J.F. Sebastian
+1  A: 

Change your loop to:

for root, dirs, files in os.walk(srcdir):
    destroot = os.path.join(destdir, root[len(srcdir):])
    for adir in dirs:
        os.makedirs(os.path.join(destroot, adir))
    for filename in files:
        sourceFile = os.path.join(root, filename)
        destFile = os.path.join(destroot, filename)
        processFile(sourceFile, destFile)
Alex Martelli
This potentially has the same problem that I pointed out for SilentGhost's answer -- e.g., if srcdir is "foo/bar", then root will be "foo/bar/baz", so "root[len(srcdir):]" will be "/baz". When you do an os.path.join, and the second argument is an absolute path (which "/baz" is, at least on unix), it will just discard the destdir portion; so you'll end up with destroot="/baz".
Edward Loper
replace `root[len(srcdir):]` by `root[len(srcdir)+len(os.sep):]`
J.F. Sebastian
A: 

There are a few relative path scripts out there that will do what you want -- namely find the relative path between two paths. E.g.:

Unfortunately, I don't think this functionality has ever been added to core python.

Edward Loper