Uruchom następujący kod z katalogu zawierającego katalog o nazwie bar
(zawierający jeden lub więcej plików) i katalog o nazwie baz
(zawierający także jeden lub więcej plików). Upewnij się, że nie ma katalogu o nazwie foo
.
import shutil
shutil.copytree('bar', 'foo')
shutil.copytree('baz', 'foo')
Nie powiedzie się z:
$ 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'
Chcę, aby działało to tak samo, jak gdybym wpisał:
$ mkdir foo
$ cp bar/* foo/
$ cp baz/* foo/
Czy muszę korzystać shutil.copy()
skopiować każdy plik w baz
pod foo
? (Po tym, jak już skopiowałem zawartość „paska” do „foo” za pomocą shutil.copytree()
?) Czy istnieje łatwiejszy / lepszy sposób?
shutil.copytree()
zachowania, aby umożliwić zapis do istniejącego katalogu, ale istnieją pewne szczegóły zachowania, które należy uzgodnić.Odpowiedzi:
To ograniczenie standardu
shutil.copytree
wydaje się arbitralne i irytujące. Obejście:Pamiętaj, że nie jest to w pełni zgodne ze standardem
copytree
:symlinks
i nieignore
określa parametrów katalogu głównegosrc
drzewa;shutil.Error
błędów na poziomie głównymsrc
;shutil.Error
dla tego poddrzewa, zamiast próbować kopiować inne poddrzewa i podbijać pojedynczeshutil.Error
.źródło
shutil.copytree
robios.makedirs(dst)
na początku. Żadna część kodu nie miałaby problemu z wcześniej istniejącym katalogiem. To trzeba zmienić. Przynajmniej podajexist_ok=False
parametr wywołaniadef 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()
, który również znajduje się w stdlib, nie ma takich ograniczeń i faktycznie zachowuje się zgodnie z oczekiwaniami. Biorąc to pod uwagę, nie ma istotnego powodu, aby spróbować rozwinąć własną ( ... zwykle zepsutą ) implementację. Brendan Abel „s odpowiedź powinna być absolutnie przyjętego rozwiązania teraz.Oto rozwiązanie, które jest częścią standardowej biblioteki:
Zobacz to podobne pytanie.
Skopiuj zawartość katalogu do katalogu za pomocą Pythona
źródło
distutils.errors.DistutilsInternalError: mkpath: 'name' must be a string
, tzn. nie akceptujePosixPath
. Potrzebujeszstr(PosixPath)
. Lista życzeń do poprawy. Poza tym wolę tę odpowiedź.Path
dziedziczyć obiektustr
Przypuszczam, że jest , podobnie jak większość wcześniejszych implementacji obiektowych ścieżek obiektowych.distutils.dir_util.copy_tree()
Jest uważany za szczegół implementacji distutils i nie jest zalecany do użytku publicznego. Prawdziwe rozwiązanie powinno zostaćshutil.copytree()
ulepszone / rozszerzone, aby zachowywało się bardziej podobniedistutils.dir_util.copy_tree()
, ale bez jego wad. W międzyczasie będę nadal używać niestandardowych funkcji pomocniczych podobnych do niektórych z innych odpowiedzi.W niewielkim stopniu poprawiono odpowiedź atzz na funkcję, w której powyższa funkcja zawsze próbuje skopiować pliki ze źródła do miejsca docelowego.
W mojej powyższej realizacji
Używam powyższej funkcji wraz z kompilacją scons. Bardzo mi to pomogło, ponieważ za każdym razem, gdy kompiluję, może nie być konieczne kopiowanie całego zestawu plików, a jedynie zmodyfikowane pliki.
źródło
if not os.path.exists(d) or os.stat(s).st_mtime - os.stat(d).st_mtime > 1:
Scalanie inspirowane przez atzz i Mital Vora:
źródło
[x for x in lst if x not in excl]
nie działa to tak samo jak copytree, który wykorzystuje dopasowanie wzorca globu. en.wikipedia.org/wiki/Glob_(programming)Python 3.8 wprowadził
dirs_exist_ok
argument doshutil.copytree
:Dlatego w przypadku Python 3.8+ powinno to działać:
źródło
dirs_exist_ok=False
domyślnie w copytree, czy pierwsza próba kopiowania nie powiedzie się?dirs_exist_ok
pierwsze wezwanie, aby zilustrować różnicę (a ponieważ katalog nie istnieje jeszcze w przykładzie OP), ale oczywiście możesz go użyć, jeśli chcesz.Dokumenty wyraźnie stwierdzają, że katalog docelowy nie powinien istnieć :
Myślę, że najlepszym rozwiązaniem jest
os.walk
drugi i wszystkie kolejne katalogi,copy2
katalogi i pliki oraz dodatkowecopystat
katalogi. W końcu to dokładnie tocopytree
, co wyjaśniono w dokumentach. Lub możeszcopy
icopystat
każdy katalog / plik ios.listdir
zamiastos.walk
.źródło
Jest to inspirowane oryginalną najlepszą odpowiedzią udzieloną przez atzz, właśnie dodałem logikę zastępowania pliku / folderu. Więc nie łączy się, ale usuwa istniejący plik / folder i kopiuje nowy:
Usuń komentarz z rmtree, aby uczynić go funkcją ruchu.
źródło
Oto moja wersja tego samego zadania:
źródło
Oto wersja inspirowana tym wątkiem, która bardziej naśladuje
distutils.file_util.copy_file
.updateonly
to bool, jeśli Prawda, kopiuje tylko pliki ze zmodyfikowanymi datami nowszymi niż istniejące,dst
chyba że podano na liście,forceupdate
niezależnie od nich.ignore
iforceupdate
oczekuj list nazw plików lub nazw folderów / plików względemsrc
i akceptuj symbole wieloznaczne w stylu uniksowym podobne doglob
lubfnmatch
.Funkcja zwraca listę skopiowanych plików (lub zostałaby skopiowana,
dryrun
jeśli ma wartość True).źródło
Poprzednie rozwiązanie ma pewne problemy, które
src
mogą zostać zastąpionedst
bez powiadomienia lub wyjątku.Dodaję
predict_error
metodę przewidywania błędów przed kopiowaniem.copytree
opiera się głównie na wersji Cyrille Pontvieux.Korzystanie
predict_error
przewidzieć wszystkie błędy na początku jest najlepszy, chyba że chcesz zobaczyć wyjątek podniesiony jeden przez drugiego, kiedy wykonaćcopytree
aż wszystkie poprawki błędów.źródło
Oto moja przepustka do problemu. Zmodyfikowałem kod źródłowy dla copytree, aby zachować oryginalną funkcjonalność, ale teraz nie występuje błąd, gdy katalog już istnieje. Zmieniłem to również, aby nie zastępowało istniejących plików, ale zachowało obie kopie, jedną o zmodyfikowanej nazwie, ponieważ było to ważne dla mojej aplikacji.
źródło
Spróbuj tego:
źródło
Oto wersja, która oczekuje
pathlib.Path
jako dane wejściowe.Zauważ, że ta funkcja wymaga Pythona 3.6, który jest pierwszą wersją Pythona, w której jako obiekt
os.listdir()
obsługuje obiekty podobne do ścieżki. Jeśli trzeba wspierać wcześniejsze wersje Pythona, można zastąpićlistdir(src)
przezlistdir(str(src))
.źródło
Zakładam, że najszybszym i najprostszym sposobem byłoby wywołanie przez Python poleceń systemowych ...
przykład..
Tar i gzip w górę katalogu .... rozpakuj i rozpakuj katalog w żądanym miejscu.
tak?
źródło