ver varias una ruta recorrer manejo importar gestion escribir directorio crear como clases carpetas carpeta archivos abrir python shutil copytree

varias - python recorrer archivos de una carpeta



¿Cómo copio un directorio completo de archivos en un directorio existente usando Python? (12)

Aquí está mi pase al problema. Modifiqué el código fuente de copytree para mantener la funcionalidad original, pero ahora no ocurre ningún error cuando el directorio ya existe. También lo cambié para que no sobrescriba los archivos existentes, sino que guarda ambas copias, una con un nombre modificado, ya que esto era importante para mi aplicación.

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)

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/

¿Debo usar shutil.copy() para copiar cada archivo en baz en foo ? (Después de que ya he copiado los contenidos de ''bar'' en ''foo'' con shutil.copytree() ?) ¿O hay una manera más fácil / mejor?


Aquí está mi versión de la misma tarea ::

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)



Aquí hay una versión inspirada en este hilo que imita más de cerca a distutils.file_util.copy_file .

updateonly es un bool si es verdadero, solo copiará los archivos con fechas modificadas más nuevos que los archivos existentes en dst menos que estén listados en forceupdate que se copiarán independientemente.

ignore y forceupdate esperan listas de nombres de archivos o carpetas / archivos relativos a src y aceptan comodines de estilo Unix similares a glob o fnmatch .

La función devuelve una lista de archivos copiados (o se copiará si dryrun si es 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


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.

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)

En mi implementación anterior

  • Crear el directorio de salida si aún no existe
  • Hacer el directorio de copia llamando recursivamente a mi propio método.
  • Cuando lleguemos a copiar realmente el archivo, verifico si el archivo está modificado, entonces solo deberíamos copiar.

Estoy usando la función anterior junto con la construcción de scons. Me ayudó mucho, ya que cada vez que compilo puede que no necesite copiar todo el conjunto de archivos ... pero solo los archivos que se modifican.


Esta limitación del shutil.copytree estándar parece arbitraria y molesta. Solución:

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)

Tenga en cuenta que no es del todo coherente con el copytree estándar:

  • no symlinks e ignore parámetros del directorio raíz del árbol src ;
  • no levanta shutil.Error por errores en el nivel raíz de src ;
  • en caso de errores durante la copia de un subárbol, levantará shutil.Error para ese subárbol en lugar de intentar copiar otros subárboles y generar un único shutil.Error combinado. shutil.Error .

Esto está inspirado en la mejor respuesta original proporcionada por atzz, acabo de agregar la lógica de reemplazar archivo / carpeta. Por lo tanto, en realidad no se fusiona, pero elimina el archivo / carpeta existente y copia el nuevo:

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)

Descomenta el rmtree para convertirlo en una función de movimiento.


La solución anterior tiene un problema que src puede sobreescribir dst sin ninguna notificación o excepción.

Agrego un método predict_error para predecir errores antes de la copia. copytree principalmente en la versión de Cyrille Pontvieux.

El uso de predict_error para predecir todos los errores al principio es lo mejor, a menos que desee ver la excepción copytree por otra al ejecutar copytree hasta que se corrija todo el error.

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)


Puede modificar shutil y obtener el efecto

Cambio

os.makedirs(dst)

A

os.makedirs(dst,exist_ok=True)


Una fusión inspirada por atzz y Mital Vora:

#!/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)

  • Mismo comportamiento que shutil.copytree , con enlaces simbólicos e ignorar parámetros
  • Crear estructura de destino de directorio si no existe
  • No fallará si ya existe el dst

supongo que la manera más rápida y simple sería hacer que python invoque los comandos del sistema ...

ejemplo..

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

Tar y gzip en el directorio ... descomprime y descomprime el directorio en el lugar deseado.

yah?


los documentos establecen explícitamente que el directorio de destino no debería existir :

El directorio de destino, nombrado por dst , no debe existir ya; se creará así como los directorios principales faltantes.

Creo que su mejor os.walk es hacer el siguiente y todos los directorios copy2 , el directorio y los archivos copystat y hacer copystat adicional para los directorios. Después de todo, eso es precisamente lo que copytree hace como se explica en los documentos. O puede copy y copy copystat cada directorio / archivo y os.listdir lugar de os.walk .