Je souhaite copier l'intégralité du contenu d'un répertoire d'un emplacement à un autre en C #.
Il ne semble pas y avoir de moyen de le faire en utilisant des System.IO
classes sans beaucoup de récursivité.
Il existe une méthode dans VB que nous pouvons utiliser si nous ajoutons une référence à Microsoft.VisualBasic
:
new Microsoft.VisualBasic.Devices.Computer().
FileSystem.CopyDirectory( sourceFolder, outputFolder );
Cela semble être un hack plutôt moche. Y a-t-il une meilleure façon?
Microsoft.VisualBasic
et nonSystem.IO
? La raison pour laquelle il n'est pas dans Mono est parce que toutes les bibliothèques qui sont considérées comme «principales» le sontSystem.[something]
- toutes les autres ne le sont pas. Je n'ai aucun problème à référencer une DLL supplémentaire, mais il y a une bonne raison pour laquelle Microsoft n'a pas inclus cette fonctionnalitéSystem.IO
.Réponses:
Beaucoup plus facile
la source
Replace
a un problème si vous avez un motif répétitif à l'intérieur du chemin, par exemple"sourceDir/things/sourceDir/things"
devrait le devenir"destinationDir/things/sourceDir/things"
, mais si vous utilisez le remplacer, il devient"destinationDir/things/destinationDir/things"
*.*
au lieu de*
? Ne voulez-vous pas aussi copier des fichiers sans extensions?Hmm, je pense avoir mal compris la question mais je vais la risquer. Quel est le problème avec la méthode simple suivante?
EDIT Étant donné que cette publication a recueilli un nombre impressionnant de votes négatifs pour une réponse aussi simple à une question tout aussi simple, permettez-moi d'ajouter une explication. Veuillez lire ceci avant de voter .
Tout d'abord, ce code n'est pas destiné à remplacer le code de la question. C'est à des fins d'illustration uniquement.
Microsoft.VisualBasic.Devices.Computer.FileSystem.CopyDirectory
effectue des tests de correction supplémentaires (par exemple, si la source et la cible sont des répertoires valides, si la source est un parent de la cible, etc.) qui manquent dans cette réponse. Ce code est probablement aussi plus optimisé.Cela dit, le code fonctionne bien . Il est (presque à l'identique) utilisé dans un logiciel mature depuis des années. À part l'inconstance inhérente présente avec toutes les manipulations d'E / S (par exemple, que se passe-t-il si l'utilisateur débranche manuellement la clé USB pendant que votre code y écrit?), Il n'y a aucun problème connu.
En particulier, je voudrais souligner que l'utilisation de la récursion ici n'est absolument pas un problème. Ni en théorie (conceptuellement, c'est la solution la plus élégante) ni en pratique: ce code ne débordera pas la pile . La pile est suffisamment grande pour gérer même les hiérarchies de fichiers profondément imbriquées. Bien avant que l'espace de pile ne devienne un problème, la limitation de la longueur du chemin d'accès au dossier entre en jeu.
Notez qu'un utilisateur malveillant pourrait être en mesure de briser cette hypothèse en utilisant des répertoires profondément imbriqués d'une lettre chacun. Je n'ai pas essayé ça. Mais juste pour illustrer le point: afin de faire déborder ce code sur un ordinateur typique, les répertoires devraient être imbriqués quelques milliers de fois. Ce n'est tout simplement pas un scénario réaliste.
la source
Copié à partir de MSDN :
la source
Essaye ça:
Vos arguments xcopy peuvent varier mais vous avez l'idée.
la source
Ou, si vous voulez aller de l'avant, ajoutez une référence à votre projet pour Microsoft.VisualBasic, puis utilisez ce qui suit:
Cependant, l'utilisation de l'une des fonctions récursives est une meilleure solution car elle n'aura pas à charger la DLL VB.
la source
System.IO.Directory
, mais c'est mieux que de le réécrire!Ce site m'a toujours beaucoup aidé, et maintenant c'est mon tour d'aider les autres avec ce que je sais.
J'espère que mon code ci-dessous sera utile à quelqu'un.
la source
Path.Combine()
. N'utilisez jamais la concaténation de chaînes pour regrouper les chemins de fichiers.source_dir.Length + 1
, nonsource_dir.Length
.Copiez le dossier récursivement sans récursivité pour éviter un débordement de pile.
la source
Voici une classe utilitaire que j'ai utilisée pour des tâches d'E / S comme celle-ci.
la source
Il n'est peut-être pas sensible aux performances, mais je l'utilise pour des dossiers de 30 Mo et cela fonctionne parfaitement. De plus, je n'ai pas aimé toute la quantité de code et de récursivité nécessaires pour une tâche aussi simple.
Remarque: ZipFile est disponible sur .NET 4.5+ dans l'espace de noms System.IO.Compression
la source
Une amélioration mineure de la réponse de d4nt, car vous voulez probablement vérifier les erreurs et ne pas avoir à changer les chemins xcopy si vous travaillez sur un serveur et une machine de développement:
la source
C'est mon code j'espère que cette aide
la source
SearchOption
indicateur sur les recherches de dossiers et de fichiers, il le fait en 4 lignes de code. Consultez également l'.HasFlag
extension maintenant sur les énumérations.Si vous aimez la réponse populaire de Konrad, mais que vous souhaitez que le
source
dossier lui - même soit sous un dossiertarget
, plutôt que de placer ses enfants sous letarget
dossier, voici le code pour cela. Il renvoie le nouveau crééDirectoryInfo
, ce qui est pratique:la source
Vous pouvez toujours utiliser ce , pris sur le site Web Microsofts.
la source
file.CopyTo(temppath, false);
dit "copiez ce fichier à cet endroit, seulement s'il n'existe pas", ce qui n'est pas la plupart du temps ce que nous voulons. Mais, je peux comprendre pourquoi c'est par défaut. Ajoutez peut-être un indicateur à la méthode de remplacement des fichiers.la version Proof de remplacement de tboswell (qui résiste à la répétition du modèle dans le chemin de fichier)
la source
Path.Combine()
. N'utilisez jamais la concaténation de chaînes pour regrouper les chemins de fichiers.Ma solution est essentiellement une modification de la réponse de @ Termininja, mais je l'ai un peu améliorée et elle semble être plus de 5 fois plus rapide que la réponse acceptée.
EDIT: La modification de @Ahmed Sabry en foreach parallèle complet produit un meilleur résultat, cependant le code utilise une fonction récursive et ce n'est pas idéal dans certaines situations.
la source
Désolé pour le code précédent, il y avait encore des bugs :( (tombé en proie au problème de pistolet le plus rapide). Ici, il est testé et fonctionne. La clé est SearchOption.AllDirectories, ce qui élimine le besoin de récursivité explicite.
la source
Voici une méthode d'extension pour DirectoryInfo à la FileInfo.CopyTo (notez le
overwrite
paramètre):la source
Utilisez cette classe.
la source
.ToList().ForEach(
(ce qui est légèrement plus de travail, de mémoire et légèrement plus lent que de simplement énumérer les répertoires directement) et comme méthode d'extension. La réponse sélectionnée utiliseSearchOption.AllDirectories
et évite la récursivité, donc je recommanderais de passer à ce modèle. De plus, vous n'avez généralement pas besoin du nom du type dans les méthodes d'extension - je le renommerais pourCopyTo()
qu'il deviennesourceDir.CopyTo(destination);
Une variante avec une seule boucle pour copier tous les dossiers et fichiers:
la source
Regex
, vous devriez probablement également faireRegex.Escape(path)
partie de votre composition d'expression (en particulier compte tenu du séparateur de chemin Windows). Vous pouvez également bénéficier de la création (et peut-être de la compilation) d'unnew Regex()
objet en dehors de la boucle, plutôt que de vous fier à la méthode statique.Mieux que n'importe quel code (méthode d'extension à DirectoryInfo avec récursivité)
la source
Copiez et remplacez tous les fichiers du dossier
la source
try
catch
throw
est également inutile.Le code ci-dessous est une suggestion de microsoft comment copier des répertoires et il est partagé par cher @iato, mais il copie simplement les sous-répertoires et les fichiers du dossier source de manière récursive et ne copie pas le dossier source lui-même (comme un clic droit -> copier ).
mais il y a un moyen délicat en dessous de cette réponse:
si vous voulez copier récursivement le contenu du dossier source et des sous - dossiers, vous pouvez simplement l'utiliser comme ceci:
mais si vous souhaitez copier le répertoire source lui-même (similaire au fait que vous avez cliqué avec le bouton droit sur le dossier source et cliqué sur copier, puis dans le dossier de destination sur lequel vous avez cliqué sur coller), vous devez utiliser comme ceci:
la source