web-dev-qa-db-fra.com

Comment copier le répertoire de manière récursive dans python et tout écraser?

J'essaie de copier /home/myUser/dir1/ et tout son contenu (et son contenu, etc.) à /home/myuser/dir2/ en python. De plus, je veux que la copie écrase tout dans dir2/.

Il ressemble à distutils.dir_util.copy_tree pourrait être le bon outil pour ce travail, mais il n’est pas certain qu’il existe quelque chose de plus facile/plus évident à utiliser pour une tâche aussi simple.

Si c'est le bon outil, comment puis-je l'utiliser? Selon le docs , il faut 8 paramètres. Dois-je réussir tous les 8 ne sont que src, dst et update, et si oui, comment (je suis nouveau en Python).

S'il y a quelque chose de mieux à faire, quelqu'un peut-il me donner un exemple et me diriger dans la bonne direction? Merci d'avance!

57
IAmYourFaja

Vous pouvez utiliser distutils.dir_util.copy_tree _ . Cela fonctionne très bien et vous n’avez pas à passer tous les arguments, seuls src et dst sont obligatoires.

Cependant, dans votre cas, vous ne pouvez pas utiliser un outil similaire, tel que shutil.copytree _ car il se comporte différemment: comme le répertoire de destination ne doit pas exister, cette fonction ne peut pas être utilisée pour écraser son contenu.

Si vous souhaitez utiliser l'outil cp comme suggéré dans la question, veuillez noter que l'utilisation du module subprocess est actuellement la méthode recommandée pour générer de nouveaux processus, comme vous pouvez le voir dans la section documentation de la fonction os.system .

54
Vicent

Jetez un coup d'œil au paquet shutil , en particulier rmtree et copytree . Vous pouvez vérifier si un fichier/chemin existe avec os.paths.exists(<path>).

import shutil
import os

def copy_and_overwrite(from_path, to_path):
    if os.path.exists(to_path):
        shutil.rmtree(to_path)
    shutil.copytree(from_path, to_path)

Vincent avait raison sur le fait que copytree ne fonctionnait pas, si les répertoires existent déjà. Donc, distutils est la version la plus intéressante. Vous trouverez ci-dessous une version corrigée de shutil.copytree. Il est fondamentalement copié 1-1, sauf le premier os.makedirs() placé derrière une construction if-else-:

import os
from shutil import *
def copytree(src, dst, symlinks=False, ignore=None):
    names = os.listdir(src)
    if ignore is not None:
        ignored_names = ignore(src, names)
    else:
        ignored_names = set()

    if not os.path.isdir(dst): # This one line does the trick
        os.makedirs(dst)
    errors = []
    for name in names:
        if name in ignored_names:
            continue
        srcname = os.path.join(src, name)
        dstname = os.path.join(dst, name)
        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:
                # Will raise a SpecialFileError for unsupported file types
                copy2(srcname, dstname)
        # catch the Error from the recursive copytree so that we can
        # continue with other files
        except Error, err:
            errors.extend(err.args[0])
        except EnvironmentError, why:
            errors.append((srcname, dstname, str(why)))
    try:
        copystat(src, dst)
    except OSError, why:
        if WindowsError is not None and isinstance(why, WindowsError):
            # Copying file access times may fail on Windows
            pass
        else:
            errors.extend((src, dst, str(why)))
    if errors:
        raise Error, errors
31
Michael

Voici une solution simple pour écraser récursivement une destination avec une source, en créant les répertoires nécessaires au fur et à mesure. Cela ne gère pas les liens symboliques, mais ce serait une simple extension (voir la réponse de @Michael ci-dessus).

def recursive_overwrite(src, dest, ignore=None):
    if os.path.isdir(src):
        if not os.path.isdir(dest):
            os.makedirs(dest)
        files = os.listdir(src)
        if ignore is not None:
            ignored = ignore(src, files)
        else:
            ignored = set()
        for f in files:
            if f not in ignored:
                recursive_overwrite(os.path.join(src, f), 
                                    os.path.join(dest, f), 
                                    ignore)
    else:
        shutil.copyfile(src, dest)
20
mgrant