Java File.renameTo()
est problématique, en particulier sous Windows, semble-t-il. Comme le dit la documentation de l' API ,
De nombreux aspects du comportement de cette méthode sont intrinsèquement dépendants de la plate-forme: l'opération de changement de nom peut ne pas être en mesure de déplacer un fichier d'un système de fichiers à un autre, elle peut ne pas être atomique et elle peut échouer si un fichier avec le chemin abstrait de destination existe déjà. La valeur de retour doit toujours être vérifiée pour s'assurer que l'opération de changement de nom a réussi.
Dans mon cas, dans le cadre d'une procédure de mise à niveau, j'ai besoin de déplacer (renommer) un répertoire qui peut contenir des gigaoctets de données (beaucoup de sous-répertoires et de fichiers de différentes tailles). Le déplacement est toujours effectué dans la même partition / lecteur, il n'est donc pas vraiment nécessaire de déplacer physiquement tous les fichiers sur le disque.
Il ne devrait y avoir aucun verrou de fichier sur le contenu du répertoire à déplacer, mais encore, assez souvent, renameTo () échoue à faire son travail et retourne false. (Je suppose juste que certains verrous de fichiers expirent peut-être de manière quelque peu arbitraire sous Windows.)
Actuellement, j'ai une méthode de secours qui utilise la copie et la suppression, mais cela craint car cela peut prendre beaucoup de temps, en fonction de la taille du dossier. J'envisage également de simplement documenter le fait que l'utilisateur peut déplacer le dossier manuellement pour éviter d'attendre des heures, potentiellement. Mais la bonne voie serait évidemment quelque chose d'automatique et rapide.
Ma question est donc la suivante: connaissez-vous une approche alternative et fiable pour effectuer un déplacement / renommer rapide avec Java sur Windows , soit avec le JDK ordinaire ou une bibliothèque externe. Ou si vous connaissez un moyen simple de détecter et de libérer les verrous de fichiers pour un dossier donné et tout son contenu (éventuellement des milliers de fichiers individuels), ce serait bien aussi.
Edit : Dans ce cas particulier, il semble que nous nous en sommes sortis renameTo()
en prenant simplement en compte quelques éléments supplémentaires; voir cette réponse .
Réponses:
Voir aussi la
Files.move()
méthode dans JDK 7.Un exemple:
la source
Pour ce que ça vaut, quelques notions supplémentaires:
Sous Windows,
renameTo()
semble échouer si le répertoire cible existe, même s'il est vide. Cela m'a surpris, comme j'avais essayé sous Linux, oùrenameTo()
réussi si la cible existait, tant qu'elle était vide.(De toute évidence, je n'aurais pas dû supposer que ce genre de chose fonctionne de la même manière sur toutes les plates-formes; c'est exactement ce que le Javadoc met en garde.)
Si vous pensez qu'il peut y avoir des verrous de fichiers persistants, attendre un peu avant le déplacement / changement de nom peut aider. (À un moment donné de notre programme d'installation / mise à jour, nous avons ajouté une action "veille" et une barre de progression indéterminée pendant environ 10 secondes, car il se peut qu'un service se bloque sur certains fichiers). Peut-être même faire un simple mécanisme de nouvelle tentative qui essaie
renameTo()
, puis attend pendant une période (qui augmente peut-être progressivement), jusqu'à ce que l'opération réussisse ou qu'un délai d'attente soit atteint.Dans mon cas, la plupart des problèmes semblent avoir été résolus en tenant compte des deux éléments ci-dessus, nous n'aurons donc pas besoin de faire un appel natif du noyau, ou quelque chose du genre, après tout.
la source
Le message original demandait "une approche alternative et fiable pour effectuer un déplacement / renommer rapide avec Java sur Windows, soit avec le JDK ordinaire ou une bibliothèque externe."
Une autre option non encore mentionnée ici est la version 1.3.2 ou ultérieure de la bibliothèque apache.commons.io , qui inclut FileUtils.moveFile () .
Il lève une IOException au lieu de renvoyer la valeur booléenne false en cas d'erreur.
Voir aussi la réponse de big lep dans cet autre fil .
la source
java.nio.file.Path.moveTo()
Dans mon cas, cela semblait être un objet mort au sein de ma propre application, qui gardait une poignée sur ce fichier. Donc, cette solution a fonctionné pour moi:
Avantage: c'est assez rapide, car il n'y a pas de Thread.sleep () avec un temps spécifique codé en dur.
Inconvénient: cette limite de 20 est un nombre codé en dur. Dans tous mes tests, i = 1 suffit. Mais pour être sûr, je l'ai laissé à 20 ans.
la source
Je sais que cela semble un peu piraté, mais pour ce pour quoi j'en ai eu besoin, il semble que les lecteurs et les écrivains tamponnés n'aient aucun problème à créer les fichiers.
Fonctionne bien pour les petits fichiers texte dans le cadre d'un analyseur, assurez-vous simplement que oldName et newName sont des chemins complets vers les emplacements des fichiers.
Vive Kactus
la source
Le morceau de code suivant n'est PAS une `` alternative '' mais a fonctionné de manière fiable pour moi sur les environnements Windows et Linux:
la source
Sur Windows, j'utilise
Runtime.getRuntime().exec("cmd \\c ")
puis j'utilise la fonction de changement de nom en ligne de commande pour renommer les fichiers. C'est beaucoup plus flexible, par exemple si vous voulez renommer l'extension de tous les fichiers txt dans un répertoire en bak, écrivez simplement ceci dans le flux de sortie:renommer * .txt * .bak
Je sais que ce n'est pas une bonne solution, mais apparemment, cela a toujours fonctionné pour moi, bien mieux que le support en ligne Java.
la source
Pourquoi pas....
fonctionne sur nwindows 7, ne fait rien si existingFile n'existe pas, mais il pourrait évidemment être mieux instrumenté pour résoudre ce problème.
la source
J'ai eu un problème similaire. Le fichier a été copié plutôt en mouvement sous Windows mais a bien fonctionné sous Linux. J'ai résolu le problème en fermant le fileInputStream ouvert avant d'appeler renameTo (). Testé sur Windows XP.
la source
Dans mon cas, l'erreur était dans le chemin du répertoire parent. Peut-être un bug, j'ai dû utiliser la sous-chaîne pour obtenir un chemin correct.
la source
Je sais que ça craint, mais une alternative est de créer un script chauve-souris qui produit quelque chose de simple comme "SUCCESS" ou "ERROR", l'invoquez, attendez qu'il soit exécuté et vérifiez ses résultats.
Runtime.getRuntime (). Exec ("cmd / c start test.bat");
Ce fil peut être intéressant. Vérifiez également la classe Process pour savoir comment lire la sortie de console d'un processus différent.
la source
Vous pouvez essayer robocopy . Ce n'est pas exactement "renommer", mais c'est très fiable.
la source
Pour déplacer / renommer un fichier, vous pouvez utiliser cette fonction:
Il est défini dans kernel32.dll.
la source
Ce qui précède est le code simple. J'ai testé sur Windows 7 et fonctionne parfaitement bien.
la source