Ejecute el siguiente código desde un directorio que contiene un directorio llamado bar
(que contiene uno o más archivos) y un directorio llamado baz
(que también contiene uno o más archivos). Asegúrese de que no haya un directorio llamado foo
.
import shutil
shutil.copytree('bar', 'foo')
shutil.copytree('baz', 'foo')
Fallará con:
$ 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'
Quiero que esto funcione de la misma manera que si hubiera escrito:
$ mkdir foo
$ cp bar/* foo/
$ cp baz/* foo/
¿Es necesario utilizar shutil.copy()
para copiar cada archivo en baz
a foo
? (¿Después de que ya he copiado el contenido de 'bar' en 'foo' con shutil.copytree()
?) ¿O hay una manera más fácil / mejor?
shutil.copytree()
el comportamiento para permitir la escritura en un directorio existente, pero hay algunos detalles de comportamiento que deben acordarse.Respuestas:
Esta limitación del estándar
shutil.copytree
parece arbitraria y molesta. Solución alterna:Tenga en cuenta que no es totalmente coherente con el estándar
copytree
:symlinks
yignore
parámetros para el directorio raíz delsrc
árbol;shutil.Error
errores en el nivel raíz desrc
;shutil.Error
para ese subárbol en lugar de intentar copiar otros subárboles y generará un solo combinadoshutil.Error
.fuente
shutil.copytree
hace unos.makedirs(dst)
al principio. Ninguna parte del código realmente tendría un problema con un directorio preexistente. Esto necesita ser cambiado. Al menos proporcione unexist_ok=False
parámetro para la llamadadef 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()
, que también reside en stdlib, no tiene esa restricción y en realidad se comporta como se esperaba. Dado eso, no hay una razón convincente para intentar desenrollar su propia implementación ( ... normalmente rota ). La respuesta de Brendan Abel debería ser absolutamente la solución aceptada ahora.Aquí hay una solución que forma parte de la biblioteca estándar:
Ver esta pregunta similar.
Copie el contenido del directorio en un directorio con python
fuente
distutils.errors.DistutilsInternalError: mkpath: 'name' must be a string
, es decir, no aceptaPosixPath
. Necesitarástr(PosixPath)
. Lista de deseos para mejorar. Aparte de este asunto, prefiero esta respuesta.Path
objeto heredestr
, supongo, como la mayoría de las implementaciones anteriores de objetos de ruta orientados a objetos ...distutils.dir_util.copy_tree()
se considera un detalle de implementación de distutils y no se recomienda para uso público. La solución real debería sershutil.copytree()
mejorar / ampliar para comportarse más comodistutils.dir_util.copy_tree()
, pero sin sus defectos. Mientras tanto, seguiré usando funciones de ayuda personalizadas similares a algunas de las que se proporcionan en otras respuestas.En una ligera mejora en la respuesta de atzz a la función donde la función anterior siempre intenta copiar los archivos de origen a destino.
En mi implementación anterior
Estoy usando la función anterior junto con scons build. Me ayudó mucho ya que cada vez que compilo no necesito copiar todo el conjunto de archivos ... sino solo los archivos que se modifican.
fuente
if not os.path.exists(d) or os.stat(s).st_mtime - os.stat(d).st_mtime > 1:
Una fusión inspirada en atzz y Mital Vora:
fuente
[x for x in lst if x not in excl]
esto no hace lo mismo que copytree, que utiliza la coincidencia de patrón global. en.wikipedia.org/wiki/Glob_(programming)Python 3.8 introdujo el
dirs_exist_ok
argumento parashutil.copytree
:Por lo tanto, con Python 3.8+ esto debería funcionar:
fuente
dirs_exist_ok=False
por defecto en copytree, ¿no fallará el primer intento de copia?dirs_exist_ok
de la primera llamada para ilustrar la diferencia (y porque el directorio aún no existe en el ejemplo de OP), pero, por supuesto, puede usarlo si lo desea.los documentos declaran explícitamente que el directorio de destino no debería existir :
Creo que su mejor opción es
os.walk
el segundo y todos los directorios,copy2
directorios y archivos consecuentes y hacer máscopystat
para directorios. Después de todo, eso es precisamente locopytree
que se explica en los documentos. O podríacopy
ycopystat
cada directorio / archivo y enos.listdir
lugar deos.walk
.fuente
Esto está inspirado en la mejor respuesta original proporcionada por atzz, acabo de agregar reemplazar la lógica de archivo / carpeta. Por lo tanto, en realidad no se fusiona, pero elimina el archivo / carpeta existente y copia el nuevo:
Descomente el rmtree para que sea una función de movimiento.
fuente
Aquí está mi versión de la misma tarea ::
fuente
Aquí hay una versión inspirada en este hilo que imita más de cerca
distutils.file_util.copy_file
.updateonly
es un bool si es True, solo copiará archivos con fechas modificadas más recientes que los archivos existentes adst
menos que se enumeren en losforceupdate
cuales se copiará independientemente.ignore
yforceupdate
esperar listas de nombres de archivos o carpetas / nombres de archivos relativossrc
y aceptar comodines de estilo Unix similares aglob
ofnmatch
.La función devuelve una lista de archivos copiados (o se copiarían si
dryrun
fuera Verdadero).fuente
La solución anterior tiene algún problema que
src
puede sobrescribirsedst
sin ninguna notificación o excepción.Agrego un
predict_error
método para predecir errores antes de copiar.copytree
principalmente basado en la versión de Cyrille Pontvieux.Lo mejor es usar
predict_error
para predecir todos los errores al principio, a menos que desee ver una excepción generada una por otra cuando se ejecutecopytree
hasta corregir todos los errores.fuente
Aquí está mi pase al problema. Modifiqué el código fuente de copytree para mantener la funcionalidad original, pero ahora no se produce ningún error cuando el directorio ya existe. También lo cambié para que no sobrescriba los archivos existentes, sino que mantenga ambas copias, una con un nombre modificado, ya que esto era importante para mi aplicación.
fuente
Prueba esto:
fuente
Aquí hay una versión que espera una
pathlib.Path
entrada.Tenga en cuenta que esta función requiere Python 3.6, que es la primera versión de Python donde
os.listdir()
admite objetos de tipo ruta como entrada. Si necesita admitir versiones anteriores de Python, puede reemplazarlistdir(src)
porlistdir(str(src))
.fuente
Supongo que la forma más rápida y simple sería hacer que Python llame a los comandos del sistema ...
ejemplo..
Tar y gzip el directorio .... descomprima y descomprima el directorio en el lugar deseado.
yah
fuente