Führen Sie den folgenden Code aus einem Verzeichnis aus, das ein Verzeichnis mit dem Namen bar
(das eine oder mehrere Dateien enthält) und ein Verzeichnis mit dem Namen baz
(das auch eine oder mehrere Dateien enthält) enthält. Stellen Sie sicher, dass kein Verzeichnis mit dem Namen vorhanden ist foo
.
import shutil
shutil.copytree('bar', 'foo')
shutil.copytree('baz', 'foo')
Es wird scheitern 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'
Ich möchte, dass dies so funktioniert, als hätte ich Folgendes eingegeben:
$ mkdir foo
$ cp bar/* foo/
$ cp baz/* foo/
Muss ich verwenden , shutil.copy()
jede Datei in kopieren baz
in foo
? (Nachdem ich den Inhalt von 'bar' bereits in 'foo' mit kopiert habe shutil.copytree()
?) Oder gibt es einen einfacheren / besseren Weg?
shutil.copytree()
des Verhaltens , um das Schreiben in ein vorhandenes Verzeichnis zu ermöglichen, aber es gibt einige Verhaltensdetails, die vereinbart werden müssen.Antworten:
Diese Einschränkung des Standards
shutil.copytree
erscheint willkürlich und ärgerlich. Problemumgehung:Beachten Sie, dass dies nicht vollständig mit dem Standard übereinstimmt
copytree
:symlinks
undignore
Parameter für das Stammverzeichnis dessrc
Baumes;shutil.Error
Fehler auf der Stammebene vonsrc
ausgelöst.shutil.Error
dieser Teilbaum ausgelöst, anstatt zu versuchen, andere Teilbäume zu kopieren und einzelne zusammen zu erhöhenshutil.Error
.quelle
shutil.copytree
macht einos.makedirs(dst)
am Start. Kein Teil des Codes hätte tatsächlich ein Problem mit einem bereits vorhandenen Verzeichnis. Dies muss geändert werden.exist_ok=False
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): if os.path.isdir(d): self.recursiveCopyTree(s, d, symlinks, ignore) else: shutil.copytree(s, d, symlinks, ignore) else: shutil.copy2(s, d)
distutils.dir_util.copy_tree()
, das sich auch in der stdlib befindet, hat keine solche Einschränkung und verhält sich tatsächlich wie erwartet. Angesichts dessen gibt es keinen zwingenden Grund, zu versuchen, Ihre eigene ( ... normalerweise defekte ) Implementierung abzuwickeln . Die Antwort von Brendan Abel sollte jetzt unbedingt die akzeptierte Lösung sein.Hier ist eine Lösung, die Teil der Standardbibliothek ist:
Siehe diese ähnliche Frage.
Kopieren Sie den Verzeichnisinhalt in ein Verzeichnis mit Python
quelle
distutils.errors.DistutilsInternalError: mkpath: 'name' must be a string
dh es akzeptiert nichtPosixPath
. Müssenstr(PosixPath)
. Wunschliste für Verbesserungen. Abgesehen von dieser Angelegenheit bevorzuge ich diese Antwort.Path
Objekt nicht von ihm erben zu lassen,str
nehme ich an, wie die meisten früheren Implementierungen objektorientierter Pfadobjekte.distutils.dir_util.copy_tree()
als Implementierungsdetail von Distutils angesehen wird und nicht für die öffentliche Verwendung empfohlen wird. Die wirkliche Lösung sollteshutil.copytree()
darin bestehen, verbessert / erweitert zu werden, um sich ähnlicher zu verhaltendistutils.dir_util.copy_tree()
, jedoch ohne Mängel. In der Zwischenzeit werde ich weiterhin benutzerdefinierte Hilfsfunktionen verwenden, die denen in anderen Antworten ähneln.Eine leichte Verbesserung gegenüber der Antwort von atzz auf die Funktion, bei der die obige Funktion immer versucht, die Dateien von der Quelle zum Ziel zu kopieren.
In meiner obigen Implementierung
Ich benutze die obige Funktion zusammen mit Scons Build. Es hat mir sehr geholfen, da ich beim Kompilieren möglicherweise nicht den gesamten Satz von Dateien kopieren muss, sondern nur die Dateien, die geändert werden.
quelle
if not os.path.exists(d) or os.stat(s).st_mtime - os.stat(d).st_mtime > 1:
Eine Fusion, die von atzz und Mital Vora inspiriert wurde:
quelle
[x for x in lst if x not in excl]
Dies entspricht nicht dem Copytree, bei dem der Glob-Pattern-Matching verwendet wird. en.wikipedia.org/wiki/Glob_(programming)Python 3.8 führte das
dirs_exist_ok
Argument ein inshutil.copytree
:Daher sollte dies mit Python 3.8+ funktionieren:
quelle
dirs_exist_ok=False
Wird der erste Kopierversuch in Copytree nicht standardmäßig fehlschlagen?dirs_exist_ok
den ersten Aufruf weggelassen, um den Unterschied zu veranschaulichen (und weil das Verzeichnis im Beispiel von OP noch nicht vorhanden ist), aber natürlich können Sie es verwenden, wenn Sie möchten.Dokumente geben ausdrücklich an, dass das Zielverzeichnis nicht existieren sollte :
Ich denke, Ihre beste Wahl ist
os.walk
das zweite und alle nachfolgenden Verzeichnisse,copy2
Verzeichnisse und Dateien und zusätzlichecopystat
Verzeichnisse. Immerhin ist es genau das, wascopytree
in den Dokumenten erklärt wird. Oder Sie könntencopy
undcopystat
jedes Verzeichnis / Datei undos.listdir
stattos.walk
.quelle
Dies ist inspiriert von der ursprünglich besten Antwort von atzz. Ich habe gerade die Logik zum Ersetzen von Dateien / Ordnern hinzugefügt. Es wird also nicht zusammengeführt, sondern die vorhandene Datei / der vorhandene Ordner gelöscht und die neue kopiert:
Kommentieren Sie den rmtree aus, um ihn zu einer Verschiebungsfunktion zu machen.
quelle
Hier ist meine Version derselben Aufgabe:
quelle
Hier ist eine von diesem Thread inspirierte Version, die genauer nachahmt
distutils.file_util.copy_file
.updateonly
ist ein Bool, wenn True, kopiert nur Dateien mit Änderungsdaten, die neuer als vorhandene Dateien sind,dst
sofern nicht aufgeführt, inforceupdate
denen unabhängig kopiert wird.ignore
undforceupdate
erwarten Sie Listen mit Dateinamen oder Ordner- / Dateinamen in Bezug aufsrc
und akzeptieren Platzhalter im Unix-Stil ähnlichglob
oderfnmatch
.Die Funktion gibt eine Liste der kopierten Dateien zurück (oder würde kopiert,
dryrun
wenn True).quelle
Die vorherige Lösung weist ein Problem auf, das
src
möglicherweisedst
ohne Benachrichtigung oder Ausnahme überschrieben wird .Ich füge eine
predict_error
Methode hinzu, um Fehler vor dem Kopieren vorherzusagen.copytree
hauptsächlich basierend auf Cyrille Pontvieux 'Version.Es
predict_error
ist am besten, zunächst alle Fehler vorherzusagen, es sei denn, Sie möchten, dass bei der Ausführung eine Ausnahme von einer anderen ausgelöst wird,copytree
bis alle Fehler behoben sind.quelle
Hier ist mein Pass zum Problem. Ich habe den Quellcode für Copytree geändert, um die ursprüngliche Funktionalität beizubehalten, aber jetzt tritt kein Fehler auf, wenn das Verzeichnis bereits vorhanden ist. Ich habe es auch geändert, damit vorhandene Dateien nicht überschrieben werden, sondern beide Kopien beibehalten werden, eine mit einem geänderten Namen, da dies für meine Anwendung wichtig war.
quelle
Versuche dies:
quelle
Hier ist eine Version, die eine
pathlib.Path
Eingabe als erwartet .Beachten Sie, dass für diese Funktion Python 3.6 erforderlich ist. Dies ist die erste Version von Python, in
os.listdir()
der pfadähnliche Objekte als Eingabe unterstützt werden. Wenn Sie frühere Versionen von Python unterstützen müssen, können Sie ersetzenlistdir(src)
durchlistdir(str(src))
.quelle
Ich würde annehmen, der schnellste und einfachste Weg wäre, Python die Systembefehle aufrufen zu lassen ...
Beispiel..
Tar und gzip das Verzeichnis .... entpacken und entpacken Sie das Verzeichnis an der gewünschten Stelle.
Yah?
quelle