0

I have looked extensively on this site and I can't see an example that fits the bill. I have 4 directories each of which contains a number of files and another directory called 'Superseded'. I am trying to write a script that will move all files in each folder into the 'Superseded' folder but I'm not having any luck.

import os, shutil
source = r'U:\Data\All\Python_Test\Exports\GLA'
dest = r'U:\Data\All\Python_Test\Exports\Superseded'
listofFiles = os.listdir(source)
 for f in listofFiles:
    fullPath = source + "/" + f
    shutil.move(fullPath, dest)

I can only get this to work for one directory and even then only when I've made the destination directory outside of the GLA directory if that makes sense.

I know there is a a os.path.isfile() module so that I can only move the files but I can't seem to get it to work. Does anybody have any ideas?

Dunuts
  • 159
  • 1
  • 8
  • are the 4 in the same folder or do you give the 4 paths manually? – mikuszefski Sep 27 '17 at 13:40
  • The 4 directories are in the same folder, it's U:\Data\All\Python_Test\Exports and it contains the four directories, each of which contains a 'Superseded' folder. – Dunuts Sep 27 '17 at 13:53

1 Answers1

0

This works for me:

import os

#from:
# https://stackoverflow.com/questions/1158076/implement-touch-using-python
# I use this to create some empty file to move around later
def touch(fname, times=None):
    fhandle = open(fname, 'a')
    try:
        os.utime(fname, times)
    finally:
        fhandle.close()


# this function is only to create the folders and files to be moved        
def create_files_in_known_folders():
    nameList=["source_dir_{:02d}".format(x) for x in range(4)]
    for name in nameList:
        path=os.path.expanduser(os.path.join("~",name))
        if not os.path.exists(path):
            os.mkdir(path)
        ssPath=os.path.join(path,"superseded")  
        if not os.path.exists(ssPath):
            os.mkdir(ssPath)  
        for i in range(3):
            filename="{}_{:02d}.dat".format(name,i)
            filepath=os.path.join(path, filename)
            if not os.path.exists(filepath):
                touch(filepath)

# THIS is actually the function doing what the OP asked for
# there many details that can be tweaked
def move_from_known_to_dest():
    # here my given names from above
    nameList=["source_dir_{:02d}".format(x) for x in range(4)]
    # and my destination path
    destPath=os.path.expanduser(os.path.join("~","dest"))
    # not interested in files that are in subfolders
    # if those would exist change to os.walk and 
    # exclude the destination folder with according if...:
    for name in nameList:
        path=os.path.expanduser(os.path.join("~",name))
        dirList=os.listdir(path)
        print path
        for fileName in dirList:
            filePath=os.path.join(path, fileName)
            print filePath
            if os.path.isfile(filePath):
                destPath=os.path.join(path,"superseded",fileName)
                print destPath
                #alternatively you can chose to 1) overwrite ()might not work 2)delete first 3) not copy
                # another option is to check for existence and if 
                # present add a number to the dest-file-name
                # use while loop to check for first non-present number 
                assert not os.path.exists(destPath), "file {} already exits".format(destPath)
                #https://stackoverflow.com/questions/8858008/how-to-move-a-file-in-python
                os.rename( filePath, destPath)



if __name__=="__main__":
    create_files_in_known_folders()
    #break here and check that filestructure and files have been created
    move_from_known_to_dest()

But, think carefully what to do if the file already exits in your destination folder. os.walk might also be something you want to look at.

Implementing several options for the copy behaviour may look like this:

import warnings

#from:
# https://stackoverflow.com/questions/2187269/python-print-only-the-message-on-warnings
formatwarning_orig = warnings.formatwarning
warnings.formatwarning = lambda message, category, filename, lineno, line=None: \
    formatwarning_orig(message, category, filename, lineno, line='')


def move_from_known_to_dest_extra(behaviour='overwrite'):
    assert behaviour in ['overwrite','leave','accumulate'], "unknown behaviour: {}".format(behaviour)
    nameList=["source_dir_{:02d}".format(x) for x in range(4)]
    destPath=os.path.expanduser(os.path.join("~","dest"))
    for name in nameList:
        path=os.path.expanduser(os.path.join("~",name))
        dirList=os.listdir(path)
        for fileName in dirList:
            filePath=os.path.join(path, fileName)
            if os.path.isfile(filePath):
                destPath=os.path.join(path,"superseded",fileName)
                # simplest case...does not exist so copy
                if not os.path.exists(destPath):
                    os.rename( filePath, destPath)
                else:
                    if behaviour=='leave':
                        warnings.warn( "Warning! Not copying file: {}; file {} already exists!".format(filePath, destPath))
                    elif behaviour =='overwrite':
                        os.remove(destPath)
                        # documentation states:
                        # On Windows, if dst already exists, OSError will be raised even if it is a file.
                        os.rename( filePath, destPath)
                        warnings.warn( "Warning!Overwriting file: {}.".format(destPath))
                    elif behaviour=='accumulate': #redundant but OK
                        addPost=0
                        while True:
                            newDestPath=destPath+"{:04d}".format(addPost)
                            if not os.path.exists(newDestPath):
                                break
                            addPost+=1
                            assert addPost < 10000, "Clean up the mess!"
                        os.rename( filePath, newDestPath)
                    else:
                        assert 0, "Unknown copy behaviour requested."

Additionally one might check for file permissions as, e.g., os.remove() may raise an exception. In this case, however, I assume that permissions are properly set by the OP.

mikuszefski
  • 3,943
  • 1
  • 25
  • 38
  • Thanks. Would you know How I could change this nameList=["U:/Data/All/PAR_Exports/{:02d}".format(x) for x in range(4)] so that it can be four folders based on characters? – Dunuts Sep 28 '17 at 09:05
  • @Dunuts Hi, you have at least two possibilities here: 1) `nameList=["U:/Data/All/PAR_Exports/{}".format(x) for x in ['a','b','c','d']]` or in case of abcd 2) `nameList=["U:/Data/All/PAR_Exports/{}".format(chr(97+x)) for x in range(4)] ` chose different offset functions for other characters. And a tip at the end. To avoid confusion in paths with `\ ` or `/` use `os.path.join()`. – mikuszefski Sep 28 '17 at 11:29