1

I am quite new to Python, so please bear with me. I was looking to write something to copy files from one directory to another. I found the following Question and Answers: Here

There, I found this answer:

def copytree(src, dst, symlinks=False, ignore=None):
for item in os.listdir(src):
    s = os.path.join(src, item)
    d = os.path.join(dst, item)
    if os.path.isdir(s):
        shutil.copytree(s, d, symlinks, ignore)
    else:
        shutil.copy2(s, d)

Which someone later added to in order to resolve some issues with it:

#!/usr/bin/python
import os
import shutil
import stat
def copytree(src, dst, symlinks = False, ignore = None):
  if not os.path.exists(dst):
    os.makedirs(dst)
    shutil.copystat(src, dst)
  lst = os.listdir(src)
  if ignore:
    excl = ignore(src, lst)
    lst = [x for x in lst if x not in excl]
  for item in lst:
    s = os.path.join(src, item)
    d = os.path.join(dst, item)
    if symlinks and os.path.islink(s):
      if os.path.lexists(d):
        os.remove(d)
      os.symlink(os.readlink(s), d)
      try:
        st = os.lstat(s)
        mode = stat.S_IMODE(st.st_mode)
        os.lchmod(d, mode)
      except:
        pass # lchmod not available
    elif os.path.isdir(s):
      copytree(s, d, symlinks, ignore)
    else:
      shutil.copy2(s, d)

I understood that shutil.copytree() had issues when the destination directory already existed and these revisions were meant to deal with it.

My question is about the symlinks and the ignore parameters that I'm seeing and not understanding what they do and how it resolves the issue.

I was able to find the definitions below, which went way over my head:

symlinks (optional) : This parameter accepts True or False, depending on which the metadata of the original links or linked links will be copied to the new tree.

ignore (optional) : If ignore is given, it must be a callable that will receive as its arguments the directory being visited by copytree(), and a list of its contents, as returned by os.listdir().

kaya3
  • 47,440
  • 4
  • 68
  • 97
bkr009
  • 45
  • 1
  • 11

1 Answers1

1

This might not be what you are looking for, but if you are able it would be way easier to code and understand to simply use your os's copy function. This can be done from python whith the os library.

def copytree(src,dst):
    os.system("cp -r "+src+" "+dst)

This example assumes you're using linux but it would work on any OS you would just have to switch 'cp -r' out for your local copy command.

Parcevel
  • 193
  • 10
  • I thought I read somewhere that this would not copy across different drives. My intention is to transfer something from a pc to a flash drive. Also, I am assuming the " " is to be filled with the paste command or does the " " just do that. – bkr009 Nov 15 '19 at 19:07
  • As long as you use full file paths in that case including mount points I see no reason why it wouldn't work as that is how the os copys things. Ex: f:\Desktop\backupme.doc d:\backup – Parcevel Nov 15 '19 at 19:10
  • Sorry I only answered the first part the " " is so that when python constructs the string there is a space between the file paths as cp is expecting. For windows I believe you'll want to use "xcopy "+src+" "+dst – Parcevel Nov 15 '19 at 19:16
  • I ended up trying to use your way, but this only copies a single file at a time and doesn't achieve what the above code is doing, where it copies an entire folder or directory. – bkr009 Nov 20 '19 at 21:36
  • That is simply a matter of using the xcopy /S flag to copy all files and subdirectories. – Parcevel Nov 21 '19 at 19:01
  • 1
    Thank you so much for sticking with me on this. This worked amazingly! Here's what I ended up using with it prompting me every time it actually saw a file to transfer: 'code' def copytree(directory1, directory2): os.system("xcopy /p /s %s %s" % (directory1, directory2)) 'code' – bkr009 Nov 21 '19 at 22:01
  • Thanks, though I did find some information stating that os.system and os.popen have been both deprecated since 2.6 and subprocess.run() should be utilized instead. – bkr009 Nov 22 '19 at 19:13
  • Which subprocess also seems to be not the best way to do it as it's a shell program. shutil seems to be the recommended process presently. It's built in rather than rather than os or subprocess. – bkr009 Nov 22 '19 at 20:09
  • I'm sure that all of those ways will work. That being said os.system is supported in the newest version of python (not depreciated). https://docs.python.org/3/library/os.html – Parcevel Nov 22 '19 at 21:00
  • Ok, understood. It's sometimes hard to keep track of what is deprecated and what's been updated. The only trouble I seem to be running in now if I remain to use os.system is that it doesn't seem to support directories with spaces in them. Would be ideal if all directories were not with spaces, but that's not how people name their folders. – bkr009 Nov 25 '19 at 13:44
  • If you put the filepath in double quotes spaces will work just fine, however you might need to use a backslash to break the double quotes if that is also how you are creating the string. See this for more info https://stackoverflow.com/questions/6376113/how-do-i-use-spaces-in-the-command-prompt – Parcevel Nov 25 '19 at 18:45
  • This did it! Because I was using double quotes in creating a string, I just used ' " '+directory+' + ' to set it – bkr009 Nov 27 '19 at 19:05