Wie kann ich ein ganzes Verzeichnis von Dateien in ein bestehendes Verzeichnis mit Python kopieren?

StackOverflow https://stackoverflow.com/questions/1868714

  •  18-09-2019
  •  | 
  •  

Frage

Führen Sie den folgenden Code aus einem Verzeichnis, das ein Verzeichnis namens bar (die eine oder mehr Dateien) und ein Verzeichnis namens baz (auch Dateien, die eine oder mehr) enthält. Stellen Sie sicher, dass es kein Verzeichnis mit dem Namen foo.

import shutil
shutil.copytree('bar', 'foo')
shutil.copytree('baz', 'foo')

Es wird nicht mit:

$ python copytree_test.py 
Traceback (most recent call last):
  File "copytree_test.py", line 5, in <module>
    shutil.copytree('baz', 'foo')
  File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/shutil.py", line 110, in copytree
  File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/os.py", line 172, in makedirs
OSError: [Errno 17] File exists: 'foo'

Das mag ich die gleiche Art und Weise arbeiten, als ob ich getippt hatte:

$ mkdir foo
$ cp bar/* foo/
$ cp baz/* foo/

Muss ich shutil.copy() verwenden, um jede Datei in baz in foo zu kopieren? (Nachdem ich bereits den Inhalt des ‚bar‘ kopiert habe in ‚foo‘ mit shutil.copytree()?) Oder ist es ein einfacherer / besserer Weg?

War es hilfreich?

Lösung

Diese Begrenzung des Standard shutil.copytree scheint willkürlich und ärgerlich. Umgehung:

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)

Beachten Sie, dass es nicht ganz im Einklang mit dem Standard copytree ist:

  • es nicht symlinks und ignore Parameter für das Stammverzeichnis des src Baum ehren;
  • es gibt keinen Anlass shutil.Error auf Fehler auf der Stammebene von src;
  • im Fall von Fehlern beim Kopieren eines Teilbaums, wird es shutil.Error für dieses Unterbaums zu erhöhen anstatt zu versuchen, andere Unterstrukturen und Steigerung der einzigen kombinierten shutil.Error zu kopieren.

Andere Tipps

Hier ist eine Lösung, die Teil der Standardbibliothek ist.

from distutils.dir_util import copy_tree
copy_tree("/a/b/c", "/x/y/z")

Sehen Sie diese ähnliche Frage.

Kopieren Verzeichnisinhalt in ein Verzeichnis mit Python

In leichter Verbesserung gegenüber atzz Antwort auf die Funktion, dass die obige Funktion versucht immer, die Dateien von der Quelle zum Ziel zu kopieren.

def copytree(src, dst, symlinks=False, ignore=None):
    if not os.path.exists(dst):
        os.makedirs(dst)
    for item in os.listdir(src):
        s = os.path.join(src, item)
        d = os.path.join(dst, item)
        if os.path.isdir(s):
            copytree(s, d, symlinks, ignore)
        else:
            if not os.path.exists(d) or os.stat(s).st_mtime - os.stat(d).st_mtime > 1:
                shutil.copy2(s, d)

In meiner obigen Implementierung

  • Erstellen des Ausgabeverzeichnis, wenn nicht bereits vorhanden ist
  • Dadurch könnte die Kopie Verzeichnis rekursiv meine eigene Methode aufrufen.
  • Wenn wir tatsächlich zu dem Kopieren der Datei ich überprüfen, ob die Datei dann modifiziert wird, nur wir sollten kopieren.

ich oben Funktion verwenden zusammen mit scons bauen. Es hat mir sehr geholfen, wie jedes Mal, wenn ich kompilieren ich kann nicht ganze Reihe von Dateien kopieren müssen .. aber nur die Dateien, die geändert werden.

A einen von atzz und Mital Vora inspiriert verschmelzen:

#!/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)
  • Das gleiche Verhalten wie shutil.copytree mit Symlinks und ignorieren Parameter
  • Verzeichnis erstellen Zielstruktur, wenn nicht existent
  • Wird nicht fehlschlagen, wenn dst ist bereits vorhanden

docs erklären ausdrücklich, dass Zielverzeichnis sollte nicht existieren :

  

Das Zielverzeichnis, durch dst genannt, darf nicht bereits vorhanden sind; es wird sowie fehlende übergeordnete Verzeichnisse erstellt.

Ich denke, die beste Wahl ist, um die zweite und alle daraus folgenden Verzeichnisse os.walk, copy2 Verzeichnis und die Dateien und tun zusätzliche copystat für Verzeichnisse. Danach ist alles genau das, was copytree wie in der Dokumentation erklärt wird. Oder Sie könnten jedes Verzeichnis / Datei und copy statt copystat os.listdir und os.walk.

Sie können shutil ändern und die Wirkung erhalten (auf meiner Version von shutil ist dieser auf der Leitung 315)

Ändern

os.makedirs(dst)

os.makedirs(dst,exist_ok=True)

Das von der ursprünglichen besten Antwort von atzz bereitgestellt inspiriert ist, habe ich nur noch Datei / Ordner-Logik ersetzen. So ist es nicht tatsächlich fusionieren, sondern löscht die vorhandene Datei / Ordner und kopiert die neue:

import shutil
import os
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.exists(d):
            try:
                shutil.rmtree(d)
            except Exception as e:
                print e
                os.unlink(d)
        if os.path.isdir(s):
            shutil.copytree(s, d, symlinks, ignore)
        else:
            shutil.copy2(s, d)
    #shutil.rmtree(src)

Kommentar- der rmtree macht es zu einer Move-Funktion.

Ich würde davon ausgehen, schnellste und einfachste Weg, um Python hätte rufen die Systembefehle ...

Beispiel ..

import os
cmd = '<command line call>'
os.system(cmd)

Tar und das Verzeichnis gzip up .... Entpacken Sie das Verzeichnis an der gewünschten Stelle.

yah?

Hier ist meine Version der gleichen Aufgabe ::

import os, glob, shutil

def make_dir(path):
    if not os.path.isdir(path):
        os.mkdir(path)


def copy_dir(source_item, destination_item):
    if os.path.isdir(source_item):
        make_dir(destination_item)
        sub_items = glob.glob(source_item + '/*')
        for sub_item in sub_items:
            copy_dir(sub_item, destination_item + '/' + sub_item.split('/')[-1])
    else:
        shutil.copy(source_item, destination_item)

Hier ist eine Version, die von diesem Thread inspiriert, die eng mehr nachahmt distutils.file_util.copy_file.

updateonly ist ein Bool Wenn das stimmt, werden nur Dateien mit geänderten Daten kopieren neuer als Dateien in dst bestehenden, es sei denn in forceupdate aufgelistet, die unabhängig kopiert.

ignore und forceupdate erwarten Listen von Dateinamen oder Ordner / Dateinamen in Bezug auf src und akzeptieren Unix-Wildcards ähnlich oder glob fnmatch.

Die Funktion gibt eine Liste von Dateien kopiert (oder würde kopiert werden, wenn dryrun wenn True).

import os
import shutil
import fnmatch
import stat
import itertools

def copyToDir(src, dst, updateonly=True, symlinks=True, ignore=None, forceupdate=None, dryrun=False):

    def copySymLink(srclink, destlink):
        if os.path.lexists(destlink):
            os.remove(destlink)
        os.symlink(os.readlink(srclink), destlink)
        try:
            st = os.lstat(srclink)
            mode = stat.S_IMODE(st.st_mode)
            os.lchmod(destlink, mode)
        except OSError:
            pass  # lchmod not available
    fc = []
    if not os.path.exists(dst) and not dryrun:
        os.makedirs(dst)
        shutil.copystat(src, dst)
    if ignore is not None:
        ignorepatterns = [os.path.join(src, *x.split('/')) for x in ignore]
    else:
        ignorepatterns = []
    if forceupdate is not None:
        forceupdatepatterns = [os.path.join(src, *x.split('/')) for x in forceupdate]
    else:
        forceupdatepatterns = []
    srclen = len(src)
    for root, dirs, files in os.walk(src):
        fullsrcfiles = [os.path.join(root, x) for x in files]
        t = root[srclen+1:]
        dstroot = os.path.join(dst, t)
        fulldstfiles = [os.path.join(dstroot, x) for x in files]
        excludefiles = list(itertools.chain.from_iterable([fnmatch.filter(fullsrcfiles, pattern) for pattern in ignorepatterns]))
        forceupdatefiles = list(itertools.chain.from_iterable([fnmatch.filter(fullsrcfiles, pattern) for pattern in forceupdatepatterns]))
        for directory in dirs:
            fullsrcdir = os.path.join(src, directory)
            fulldstdir = os.path.join(dstroot, directory)
            if os.path.islink(fullsrcdir):
                if symlinks and dryrun is False:
                    copySymLink(fullsrcdir, fulldstdir)
            else:
                if not os.path.exists(directory) and dryrun is False:
                    os.makedirs(os.path.join(dst, dir))
                    shutil.copystat(src, dst)
        for s,d in zip(fullsrcfiles, fulldstfiles):
            if s not in excludefiles:
                if updateonly:
                    go = False
                    if os.path.isfile(d):
                        srcdate = os.stat(s).st_mtime
                        dstdate = os.stat(d).st_mtime
                        if srcdate > dstdate:
                            go = True
                    else:
                        go = True
                    if s in forceupdatefiles:
                        go = True
                    if go is True:
                        fc.append(d)
                        if not dryrun:
                            if os.path.islink(s) and symlinks is True:
                                copySymLink(s, d)
                            else:
                                shutil.copy2(s, d)
                else:
                    fc.append(d)
                    if not dryrun:
                        if os.path.islink(s) and symlinks is True:
                            copySymLink(s, d)
                        else:
                            shutil.copy2(s, d)
    return fc

Die bisherige Lösung hat einige Problem, das src ohne Benachrichtigung oder Ausnahme kann überschrieben dst.

Ich füge einen predict_error Methode Fehler vor copy.copytree hauptsächlich Basis auf Cyrille Pontvieux Version zu prognostizieren.

predict_error Verwendung aller Fehler zunächst vorherzusagen am besten ist, es sei denn, Sie Ausnahme mögen angehoben durch ein anderes sehen, wenn copytree ausgeführt werden, bis alle Fehler beheben.

def predict_error(src, dst):  
    if os.path.exists(dst):
        src_isdir = os.path.isdir(src)
        dst_isdir = os.path.isdir(dst)
        if src_isdir and dst_isdir:
            pass
        elif src_isdir and not dst_isdir:
            yield {dst:'src is dir but dst is file.'}
        elif not src_isdir and dst_isdir:
            yield {dst:'src is file but dst is dir.'}
        else:
            yield {dst:'already exists a file with same name in dst'}

    if os.path.isdir(src):
        for item in os.listdir(src):
            s = os.path.join(src, item)
            d = os.path.join(dst, item)
            for e in predict_error(s, d):
                yield e


def copytree(src, dst, symlinks=False, ignore=None, overwrite=False):
    '''
    would overwrite if src and dst are both file
    but would not use folder overwrite file, or viceverse
    '''
    if not overwrite:
        errors = list(predict_error(src, dst))
        if errors:
            raise Exception('copy would overwrite some file, error detail:%s' % errors)

    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:
            if not overwrite:
                if os.path.exists(d):
                    continue
            shutil.copy2(s, d)

Hier ist mein Pass auf das Problem. Ich änderte den Quellcode für copytree die ursprüngliche Funktionalität zu halten, aber jetzt kein Fehler tritt auf, wenn das Verzeichnis bereits vorhanden. Habe ich es auch so nicht vorhandene Dateien überschreibt, sondern hält vielmehr beide Kopien, eines mit einem geänderten Namen, da dies für meine Anwendung wichtig war.

import shutil
import os


def _copytree(src, dst, symlinks=False, ignore=None):
    """
    This is an improved version of shutil.copytree which allows writing to
    existing folders and does not overwrite existing files but instead appends
    a ~1 to the file name and adds it to the destination path.
    """

    names = os.listdir(src)
    if ignore is not None:
        ignored_names = ignore(src, names)
    else:
        ignored_names = set()

    if not os.path.exists(dst):
        os.makedirs(dst)
        shutil.copystat(src, dst)
    errors = []
    for name in names:
        if name in ignored_names:
            continue
        srcname = os.path.join(src, name)
        dstname = os.path.join(dst, name)
        i = 1
        while os.path.exists(dstname) and not os.path.isdir(dstname):
            parts = name.split('.')
            file_name = ''
            file_extension = parts[-1]
            # make a new file name inserting ~1 between name and extension
            for j in range(len(parts)-1):
                file_name += parts[j]
                if j < len(parts)-2:
                    file_name += '.'
            suffix = file_name + '~' + str(i) + '.' + file_extension
            dstname = os.path.join(dst, suffix)
            i+=1
        try:
            if symlinks and os.path.islink(srcname):
                linkto = os.readlink(srcname)
                os.symlink(linkto, dstname)
            elif os.path.isdir(srcname):
                _copytree(srcname, dstname, symlinks, ignore)
            else:
                shutil.copy2(srcname, dstname)
        except (IOError, os.error) as why:
            errors.append((srcname, dstname, str(why)))
        # catch the Error from the recursive copytree so that we can
        # continue with other files
        except BaseException as err:
            errors.extend(err.args[0])
    try:
        shutil.copystat(src, dst)
    except WindowsError:
        # can't copy file access times on Windows
        pass
    except OSError as why:
        errors.extend((src, dst, str(why)))
    if errors:
        raise BaseException(errors)

Versuchen Sie folgendes:

import os,shutil

def copydir(src, dst):
  h = os.getcwd()
  src = r"{}".format(src)
  if not os.path.isdir(dst):
     print("\n[!] No Such directory: ["+dst+"] !!!")
     exit(1)

  if not os.path.isdir(src):
     print("\n[!] No Such directory: ["+src+"] !!!")
     exit(1)
  if "\\" in src:
     c = "\\"
     tsrc = src.split("\\")[-1:][0]
  else:
    c = "/"
    tsrc = src.split("/")[-1:][0]

  os.chdir(dst)
  if os.path.isdir(tsrc):
    print("\n[!] The Directory Is already exists !!!")
    exit(1)
  try:
    os.mkdir(tsrc)
  except WindowsError:
    print("\n[!] Error: In[ {} ]\nPlease Check Your Dirctory Path !!!".format(src))
    exit(1)
  os.chdir(h)
  files = []
  for i in os.listdir(src):
    files.append(src+c+i)
  if len(files) > 0:
    for i in files:
        if not os.path.isdir(i):
            shutil.copy2(i, dst+c+tsrc)

  print("\n[*] Done ! :)")

copydir("c:\folder1", "c:\folder2")
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top