1

I need to copy the files with certain patterns. I need to perform the non recursive copy on a given directory using shutil. I tried this code given below with performs recursive copy. Is there any options to specify in it to do the non recursive copy.

    from fnmatch import fnmatch, filter
    from os.path import isdir, join
    from shutil import copytree, ignore_patterns

    src_directory = r'PATH'
    dst_directory = r'PATH'
    copytree(src_directory, ignored_directory,ignore=ignore_patterns('*.txt'))
4

3 回答 3

2

Make sure the destination directory exists first. Then create a list of all the files to ignore with glob.glob. Then iterate over all the file and directories in the src directory and copy each file to the dst directory if it is a file and it is not in the ignore list:

import os, shutil, glob
src = 'my_dir'
dst = 'my_dir_cp'

try:
    os.mkdir(dst)
except FileExistsError:
    pass

ignore = glob.glob(os.path.join(src, '*.txt'))
for file in os.listdir(src):
    file = os.path.join(src, file)
    if file not in ignore and os.path.isfile(file):
        shutil.copy(file, dst)

A full example:

$ ls my_dir
bob  cat.txt  fish  jim
$ python -q
>>> import os, shutil, glob
>>> src = 'my_dir'
>>> dst = 'my_dir_cp'
>>> 
>>> try:
...     os.mkdir(dst)
... except FileExistsError:
...     pass
... 
>>> ignore = glob.glob(os.path.join(src, '*.txt'))
>>> for file in os.listdir(src):
...     file = os.path.join(src, file)
...     if file not in ignore and os.path.isfile(file):
...         shutil.copy(file, dst)
... 
'my_dir_cp/jim'
'my_dir_cp/bob'
>>> 
$ ls my_dir_cp
bob  jim

If you want to be able to ignore multiple glob patterns, then you can glob.glob each of them and concatenate the results together (in a list-comprehension):

import os, shutil, glob
src = 'my_dir'
dst = 'my_dir_cp'

try:
    os.mkdir(dst)
except FileExistsError:
    pass

patterns_to_ignore = ['*.txt', '*.bat']
ignore = [e for p in patterns_to_ignore for e in glob.glob(os.path.join(src, p))]
for file in os.listdir(src):
    file = os.path.join(src, file)
    if file not in ignore and os.path.isfile(file):
        shutil.copy(file, dst)
于 2018-08-29T10:26:26.167 回答
1

This is more of a hack but will copy all the files in a directory to destination directory non recursively. You could use glob or regex to ignore files -

import re

def copytree(src, dst):
     for item in [f for f in os.listdir(src) if os.path.isfile(os.path.join(src, f)) if not re.match(f, '[.]txt$')]:
         s = os.path.join(src, item)
         d = os.path.join(dst, item)
         shutil.copy2(s, d)
于 2018-08-29T10:42:08.323 回答
0

As you have chosen to use copytree from shutil, be aware that any solution in which you loop over the files to copy each one leaves out many nice features of copytree, such as symlink handling, copying the file metadata, etc.

You can keep all the extras by creating a non-recursive copytree called copyfiles. copyfiles works identically to copytree, except that it extends the ignore parameter to also ignore folders while copying.

import shutil, os

def copyfiles(src, dst, ignore=lambda a, b: set(), **kwargs):
    return shutil.copytree(src, dst, ignore=lambda s, names: set(ignore(s, names)).union(set(filter(lambda name: os.path.isdir(os.path.join(s, name)), names))), **kwargs)
# use copyfiles like so:

copyfiles(src_directory, dst_directory, ignore=shutil.ignore_patterns('*.txt')) # copies non-recursively
于 2021-04-04T13:44:40.237 回答