87 votes

Comment copier un répertoire de manière récursive en python et tout écraser ?

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

Il regarde comme distutils.dir_util.copy_tree pourrait être le bon outil pour ce travail, mais je ne suis pas sûr qu'il y ait quelque chose de plus facile/plus évident à utiliser pour une tâche aussi simple.

Si c'est le bon outil, comment dois-je l'utiliser ? Selon le docs il y a 8 paramètres qu'il faut prendre. Dois-je passer les 8 paramètres ou seulement src , dst y update et si oui, comment (je suis tout nouveau en Python).

S'il existe quelque chose de mieux, quelqu'un peut-il me donner un exemple et m'indiquer la bonne direction ? Merci d'avance !

75voto

Vicent Points 5152

Vous pouvez utiliser distutils.dir_util.copy_tree . Cela fonctionne très bien et vous n'avez pas besoin de passer tous les arguments, seulement src y dst sont obligatoires.

Cependant, dans votre cas, vous ne pouvez pas utiliser un outil similaire tel que shutil.copytree car elle 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 voulez utiliser le cp comme suggéré dans les commentaires de la question, attention à ce que l'utilisation de l'outil subprocess est actuellement la méthode recommandée pour faire naître de nouveaux processus, comme vous pouvez le voir dans le module documentation de la fonction os.system .

55voto

Michael Points 1462

Jetez un coup d'œil à la shutil paquet, en particulier rmtree y 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 copytree ne fonctionne pas, si les répertoires existent déjà. Donc distutils est la version la plus agréable. Vous trouverez ci-dessous une version corrigée de shutil.copytree . Il est essentiellement copié 1-1, sauf que le premier os.makedirs() derrière une structure 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

36voto

mgrant Points 40

Voici une solution simple pour écraser récursivement une destination avec une source, en créant tous les répertoires nécessaires au fur et à mesure. Cela ne gère pas les liens symboliques, mais ce serait une extension simple (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)

31voto

orthocresol Points 465

Dans Python 3.8, l'option dirs_exist_ok argument de mot-clé a été ajouté a shutil.copytree() :

dirs_exist_ok dicte s'il faut soulever une exception en cas dst ou tout répertoire parent manquant existe déjà.

Ainsi, la procédure suivante fonctionnera dans les versions récentes de Python, même si le répertoire de destination existe déjà :

shutil.copytree(src, dest, dirs_exist_ok=True)  # 3.8+ only!

L'un de ses principaux avantages est qu'il est plus souple que les autres. distutils.dir_util.copy_tree() car il prend des arguments supplémentaires concernant les fichiers à ignorer, etc. la documentation ). En plus de cela, les PEP 632 indique également que distutils sera déprécié et par la suite supprimé dans les futures versions de Python 3.

1voto

Raju buddha Points 21

Ma réponse simple.

def get_files_tree(src="src_path"):
    req_files = []
    for r, d, files in os.walk(src):
        for file in files:
            src_file = os.path.join(r, file)
            src_file = src_file.replace('\\', '/')
            if src_file.endswith('.db'):
                continue
            req_files.append(src_file)

    return req_files
def copy_tree_force(src_path="",dest_path=""):
    """
    make sure that all the paths has correct slash characters.
    """
    for cf in get_files_tree(src=src_path):
        df= cf.replace(src_path, dest_path)
        if not os.path.exists(os.path.dirname(df)):
            os.makedirs(os.path.dirname(df))
        shutil.copy2(cf, df)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X