157 votes

Copier un fichier ou un répertoire en Python

Python semble avoir des fonctions pour copier des fichiers (par exemple shutil.copy) et des fonctions pour copier des répertoires (par exemple shutil.copytree) mais je n'ai pas trouvé de fonction qui gère les deux. Bien sûr, il est trivial de vérifier si vous voulez copier un fichier ou un répertoire, mais cela semble être une omission étrange.

N'y a-t-il vraiment aucune fonction standard qui fonctionne comme la commande unix "cp", c'est-à-dire qui supporte à la fois les répertoires et les fichiers ? Quelle serait la manière la plus élégante de contourner ce problème en Python ?

edit : Quand je dis "cp" je veux dire "cp -r". Désolé pour ça. Et je veux copier tous les répertoires récursivement (comme le font "cp -r" et shutil.copytree).

3 votes

Oui, c'est le bordel. C'est l'un des endroits où, en essayant de refléter les appels système sous-jacents, Python rend l'interface visible pire. Bien qu'il ne soit pas difficile de passer de copy-file à copy-tree, cela n'aurait pas dû être nécessaire. Vous pourriez peut-être déposer une demande d'amélioration sur le bug tracker de Python pour permettre à copytree pour copier un seul fichier ?

0 votes

Je pense que copy_tree est ce que vous recherchez.

192voto

tzot Points 32224

Je vous suggère d'abord d'appeler shutil.copytree et si une exception est levée, réessayer avec shutil.copy .

import shutil, errno

def copyanything(src, dst):
    try:
        shutil.copytree(src, dst)
    except OSError as exc: # python >2.5
        if exc.errno == errno.ENOTDIR:
            shutil.copy(src, dst)
        else: raise

31 votes

Je pense qu'il serait beaucoup plus propre de vérifier simplement si src est un répertoire en utilisant os.path.isdir(src) au lieu d'attraper une exception comme celle-ci. Ou y a-t-il une raison particulière d'utiliser une exception à la place ?

44 votes

1) Parce que dans le monde des Pythons, l'EAFP (il est plus facile de demander pardon que de demander la permission) est préféré au LBYL (regarde avant de sauter). Je peux vous fournir des liens à ce sujet, si cela vous semble nouveau. 2) La fonction de la bibliothèque vérifie déjà indirectement ce point, alors pourquoi répéter la vérification ? 3) rien n'empêche la fonction shutil.copytree d'améliorer et de gérer les deux cas à l'avenir. 4) Les exceptions ne sont pas si exceptionnelles en Python ; par exemple, une itération s'arrête en lançant une exception StopIteration.

3 votes

Dans ce cas, le traitement de l'exception prend 6 lignes, tandis que la vérification du type prend 4 lignes. Ce n'est pas grand-chose, mais cela s'additionne à la fin. De plus, comme vous le dites, copytree pourrait un jour très bien supporter les fichiers également. Mais il est impossible de dire à quoi ressemblera cette implémentation. Peut-être qu'elle lancera une exception dans certaines circonstances où copy fonctionne ? Dans ce cas, mon code cesserait soudainement de fonctionner juste à cause de la fonctionnalité ajoutée. Mais vous avez probablement raison, les exceptions sont assez courantes en Python, ce qui m'ennuie beaucoup, mais c'est probablement parce que je ne semble jamais m'y habituer

14voto

mondieki Points 799

Pour ajouter Tzot y gns réponses, voici une autre façon de copier des fichiers et des dossiers de manière récursive. (Python 3.X)

import os, shutil

root_src_dir = r'C:\MyMusic'    #Path/Location of the source directory
root_dst_dir = 'D:MusicBackUp'  #Path to the destination folder

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.copy(src_file, dst_dir)

Si c'est votre première fois et que vous ne savez pas comment copier des fichiers et des dossiers de manière récursive, j'espère que cela vous aidera.

6voto

gms Points 168

shutil.copy y shutil.copy2 sont en train de copier des fichiers.

shutil.copytree copie un dossier avec tous les fichiers et tous les sous-dossiers. shutil.copytree utilise shutil.copy2 pour copier les fichiers.

Donc l'analogie avec cp -r vous dites que c'est le shutil.copytree parce que cp -r cible et copie un dossier et ses fichiers/sous-dossiers comme suit shutil.copytree . Sans le -r cp copie des fichiers comme shutil.copy y shutil.copy2 faire.

1 votes

Je ne pense pas que vous ayez compris la question. Essayez shutil.copytree('C:\myfile.txt', 'C:\otherfile') . Ça ne marche pas. C'est ce que l'OP demandait... il y a 7 ans.

0 votes

Bien sûr que ça ne marche pas. Comme cp ne fonctionne pas avec les dossiers. Vous avez besoin d'une option spéciale. copy et copytree sont les meilleurs moyens de gérer la copie. Si copytree pouvait cibler les fichiers, il serait facile de faire des erreurs. Vous devez savoir ce que vous ciblez à la fois avec Linux et Python. C'est difficile. De plus, quelqu'un d'autre l'a commenté ici, mais en voyant la question et les réponses, je n'ai pas pu résister à l'envie de répondre. La manière élégante est de savoir ce que vous voulez faire et non une copie universelle sans aucun contrôle.

4voto

Emmanuel Points 91

La méthode la plus rapide et la plus élégante que j'ai trouvée jusqu'à présent est d'utiliser la fonction copier_arbre fonction de distutils.dir_util paquetage natif :

import distutils.dir_util
from_dir = "foo/bar"
to_dir = "truc/machin"
distutils.dir_util.copy_tree(from_dir, to_dir)

1voto

James Polley Points 4258

Unix cp ne supporte pas à la fois les répertoires et les fichiers :

betelgeuse:tmp james$ cp source/ dest/
cp: source/ is a directory (not copied).

Pour que cp copie un répertoire, vous devez lui indiquer manuellement qu'il s'agit d'un répertoire, en utilisant l'option '-r'.

Il y a une certaine déconnexion ici cependant - cp -r lorsqu'on lui passe un nom de fichier comme source, copiera volontiers le fichier unique ; copytree ne le fera pas.

2 votes

docs.python.org/library/shutil.html inclut le code de copytree() qui démontre la manipulation de fichiers ordinaires, de liens symboliques et de répertoires.

1 votes

Cette réponse ne répond pas à la question. Elle devrait être un commentaire, pas une réponse.

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