2011-09-14 61 views
51

Tengo un directorio, 'Dst Directory', que tiene archivos y carpetas y tengo 'src Directory' que también tiene archivos y carpetas. Lo que quiero hacer es mover los contenidos de 'src Directory' a 'Dst Directory' y sobrescribir cualquier archivo que exista con el mismo nombre. Entonces, por ejemplo, 'Src Directory \ file.txt' debe moverse a 'Dst Directory' y sobrescribir el archivo existente .txt. Lo mismo aplica para algunas carpetas, moviendo una carpeta y fusionando los contenidos con la misma carpeta en 'dst directory'Python - Mover y sobrescribir archivos y carpetas

Actualmente estoy usando shutil.move para mover el contenido de src a dst pero no lo hará si los archivos ya existen y no fusionará carpetas; simplemente colocará la carpeta dentro de la carpeta existente.

Actualización: para aclarar un poco las cosas; Lo que estoy haciendo es descomprimir un archivo en el Directorio Dst y luego mover los contenidos del Directorio Src allí y volver a realizar la actualización, actualizando de manera efectiva los archivos en el archivo zip. Esto se repetirá para agregar nuevos archivos o nuevas versiones de archivos, etc. por lo que es necesario sobrescribir e integrar

Resuelto: He resuelto mi problema utilizando distutils.dir_util.copy_tree (src, dst), esto copia las carpetas y archivos del directorio src al directorio dst y sobrescribe/fusiona donde sea necesario. Espero que ayude a algunas personas!

Espero que tenga sentido, gracias!

+0

Tenga en cuenta que [ 'distutils.dir_util.copy_tree'] (https://docs.python.org/dev /distutils/apiref.html#distutils.dir_util.copy_tree) no puede copiar archivos especiales, por ej. [named pipes] (https://en.wikipedia.org/wiki/Named_pipe) (arroja 'distutils.errors.DistutilsFileError'). –

Respuesta

35

En su lugar, use copy(), que está dispuesto a sobrescribir los archivos de destino. Si luego quieres que el primer árbol se vaya, solo rmtree() por separado una vez que hayas terminado de iterar sobre él.

http://docs.python.org/library/shutil.html#shutil.copy

http://docs.python.org/library/shutil.html#shutil.rmtree

Actualización:

hacen un os.walk() sobre el árbol de fuentes. Para cada directorio, verifique si existe en el lado de destino y os.makedirs() si falta. Para cada archivo, simplemente shutil.copy() y el archivo se creará o sobrescribirá, según corresponda.

+0

copy() can ' t copiar carpetas, ¿o sí? – Artharos

+0

No, pero 'move()' en cada archivo tampoco crea los directorios de destino, así que asumí que su código ya tenía un 'os.makedirs()' en las carpetas de destino que no existían. Ah! Creo que ahora entiendo, ¿estaba haciendo un 'move()' en el * whole * árbol a la vez? Gotchya. Actualizaré mi respuesta. –

+0

Gracias por la actualización, el problema es que los archivos que se copian cambian constantemente (se agregan nuevos archivos, etc.) por lo que tendré que actualizar el código cada vez que agregué nuevos archivos para mover, si es que lo entiende. De todos modos, lo logré con distutils.dir_util.copy_tree (src, dst) que copia las carpetas y archivos y sobrescribe/fusiona donde sea necesario, gracias por la ayuda – Artharos

1

Echa un vistazo a: os.remove para eliminar los archivos existentes.

+0

Problema con eso es que los archivos que deseo agregar a la carpeta cambiarán (se agregarán nuevos y se actualizarán los antiguos), así que no puedo tener una lista establecida de qué eliminar, aunque – Artharos

44

Esto pasará por el directorio de origen, crear todos los directorios que aún no existen en el directorio de destino, y mover archivos de origen en el directorio de destino:

import os 
import shutil 

root_src_dir = 'Src Directory\\' 
root_dst_dir = 'Dst Directory\\' 

for src_dir, dirs, files in os.walk(root_src_dir): 
    dst_dir = src_dir.replace(root_src_dir, root_dst_dir, 1) 
    if not os.path.exists(dst_dir): 
     os.makedirs(dst_dir) 
    for file_ in files: 
     src_file = os.path.join(src_dir, file_) 
     dst_file = os.path.join(dst_dir, file_) 
     if os.path.exists(dst_file): 
      os.remove(dst_file) 
     shutil.move(src_file, dst_dir) 

Los archivos preexistentes se eliminará primero (a través de os.remove) antes de reemplazarlo por el archivo fuente correspondiente. Cualquier archivo o directorio que ya exista en el destino pero no en el origen permanecerá intacto.

+3

Eso está bien, ¡gracias por eso! Creo que eso es lo que Brandon Craig Rhodes estaba hablando, ¡pero gracias por darnos un fragmento! Lamentablemente no puede tener dos respuestas correctas ^^ – Artharos

+1

No hay problema. :) Afortunadamente, cada una de nuestras respuestas es útil. –

+2

Y copiarlos es tan fácil como reemplazar "shutil.move" por "shutil.copy". – Karoh

6

Como ninguna de las anteriores funcionó para mí, entonces escribí mi propia función recursiva. Llamar a la función copyTree (dir1, dir2) para fusionar directorios. Ejecutar en plataformas multiples Linux y Windows.

def forceMergeFlatDir(srcDir, dstDir): 
    if not os.path.exists(dstDir): 
     os.makedirs(dstDir) 
    for item in os.listdir(srcDir): 
     srcFile = os.path.join(srcDir, item) 
     dstFile = os.path.join(dstDir, item) 
     forceCopyFile(srcFile, dstFile) 

def forceCopyFile (sfile, dfile): 
    if os.path.isfile(sfile): 
     shutil.copy2(sfile, dfile) 

def isAFlatDir(sDir): 
    for item in os.listdir(sDir): 
     sItem = os.path.join(sDir, item) 
     if os.path.isdir(sItem): 
      return False 
    return True 


def copyTree(src, dst): 
    for item in os.listdir(src): 
     s = os.path.join(src, item) 
     d = os.path.join(dst, item) 
     if os.path.isfile(s): 
      if not os.path.exists(dst): 
       os.makedirs(dst) 
      forceCopyFile(s,d) 
     if os.path.isdir(s): 
      isRecursive = not isAFlatDir(s) 
      if isRecursive: 
       copyTree(s, d) 
      else: 
       forceMergeFlatDir(s, d) 
+0

Este es el único que funciona – user1447414

+0

¿Qué situaciones no le funcionaron cuando usó otras respuestas? – cgmb

+0

Vale la pena señalar, si src tiene un archivo con el mismo nombre que un directorio en dst, esta solución colocará el archivo dentro del directorio que comparte su nombre, mientras que [la solución de Ray Vega] (http://stackoverflow.com/a/ 7420617/331041) lanzará 'OSError: [Errno 21] Es un directorio'. – cgmb

0

Tuve un problema similar. Quería mover archivos y estructuras de carpetas y sobrescribir los archivos existentes, pero no eliminar nada que esté en la estructura de la carpeta de destino.

Lo resolví usando os.walk(), llamando recursivamente a mi función y usando shutil.move() en archivos que quería sobrescribir y carpetas que no existían.

Funciona como shutil.move(), pero con la ventaja de que los archivos existentes solo se sobrescriben, pero no se eliminan.

import os 
import shutil 

def moverecursively(source_folder, destination_folder): 
    basename = os.path.basename(source_folder) 
    dest_dir = os.path.join(destination_folder, basename) 
    if not os.path.exists(dest_dir): 
     shutil.move(source_folder, destination_folder) 
    else: 
     dst_path = os.path.join(destination_folder, basename) 
     for root, dirs, files in os.walk(source_folder): 
      for item in files: 
       src_path = os.path.join(root, item) 
       if os.path.exists(dst_file): 
        os.remove(dst_file) 
       shutil.move(src_path, dst_path) 
      for item in dirs: 
       src_path = os.path.join(root, item) 
       moverecursively(src_path, dst_path) 
3

Si también necesita sobrescribir archivos con un solo uso de la bandera leer esto:

def copyDirTree(root_src_dir,root_dst_dir): 
""" 
Copy directory tree. Overwrites also read only files. 
:param root_src_dir: source directory 
:param root_dst_dir: destination directory 
""" 
for src_dir, dirs, files in os.walk(root_src_dir): 
    dst_dir = src_dir.replace(root_src_dir, root_dst_dir, 1) 
    if not os.path.exists(dst_dir): 
     os.makedirs(dst_dir) 
    for file_ in files: 
     src_file = os.path.join(src_dir, file_) 
     dst_file = os.path.join(dst_dir, file_) 
     if os.path.exists(dst_file): 
      try: 
       os.remove(dst_file) 
      except PermissionError as exc: 
       os.chmod(dst_file, stat.S_IWUSR) 
       os.remove(dst_file) 

     shutil.copy(src_file, dst_dir) 
Cuestiones relacionadas