Java File.renameTo()
é problemático, especialmente no Windows, ao que parece. Como diz a documentação da API ,
Muitos aspectos do comportamento deste método são inerentemente dependentes da plataforma: A operação de renomeação pode não ser capaz de mover um arquivo de um sistema de arquivos para outro, pode não ser atômico e pode não ter sucesso se um arquivo com o nome de caminho abstrato de destino já existe. O valor de retorno deve sempre ser verificado para garantir que a operação de renomeação foi bem-sucedida.
No meu caso, como parte de um procedimento de atualização, preciso mover (renomear) um diretório que pode conter gigabytes de dados (muitos subdiretórios e arquivos de tamanhos variados). A movimentação é sempre feita na mesma partição / unidade, então não há necessidade real de mover fisicamente todos os arquivos no disco.
Não deve haver nenhum bloqueio de arquivo para o conteúdo do diretório a ser movido, mas ainda, muitas vezes, renameTo () falha em fazer seu trabalho e retorna falso. (Estou apenas supondo que talvez alguns bloqueios de arquivo expirem um tanto arbitrariamente no Windows.)
Atualmente, tenho um método alternativo que usa copiar e excluir, mas isso é uma droga porque pode demorar muito , dependendo do tamanho da pasta. Também estou pensando em simplesmente documentar o fato de que o usuário pode mover a pasta manualmente para evitar esperar horas, potencialmente. Mas o Caminho Certo obviamente seria algo automático e rápido.
Portanto, minha pergunta é: você conhece uma abordagem alternativa e confiável para fazer uma rápida mudança / renomeação com Java no Windows , seja com JDK simples ou alguma biblioteca externa. Ou se você conhece uma maneira fácil de detectar e liberar qualquer bloqueio de arquivo para uma determinada pasta e todo o seu conteúdo (possivelmente milhares de arquivos individuais), também não há problema.
Edit : Neste caso específico, parece que escapamos usando apenas renameTo()
levando mais algumas coisas em consideração; veja esta resposta .
Respostas:
Veja também o
Files.move()
método em JDK 7.Um exemplo:
fonte
Para valer a pena, mais algumas noções:
No Windows,
renameTo()
parece falhar se o diretório de destino existir, mesmo se estiver vazio. Isso me surpreendeu, pois já havia tentado no Linux, onde davarenameTo()
certo se o target existisse, desde que estivesse vazio.(Obviamente, eu não deveria ter assumido que esse tipo de coisa funciona da mesma forma em todas as plataformas; é exatamente sobre isso que o Javadoc avisa.)
Se você suspeitar que pode haver alguns bloqueios de arquivo persistentes, esperar um pouco antes de mover / renomear pode ajudar. (Em um ponto em nosso instalador / atualizador, adicionamos uma ação de "suspensão" e uma barra de progresso indeterminado por cerca de 10 segundos, porque pode haver um serviço pendurado em alguns arquivos). Talvez até mesmo faça um mecanismo de nova tentativa simples que tenta
renameTo()
e depois espera por um período (que pode aumentar gradualmente), até que a operação seja bem-sucedida ou algum tempo limite seja atingido.No meu caso, a maioria dos problemas parece ter sido resolvida levando-se ambos os itens acima em consideração, então não precisaremos fazer uma chamada de kernel nativo, ou algo parecido, afinal.
fonte
A postagem original solicitava "uma abordagem alternativa e confiável para mover / renomear rapidamente com Java no Windows, seja com JDK simples ou alguma biblioteca externa".
Outra opção não mencionada ainda aqui é v1.3.2 ou posterior do biblioteca apache.commons.io , que inclui FileUtils.moveFile () .
Ele lança uma IOException em vez de retornar falso booleano em caso de erro.
Veja também a resposta de big lep neste outro tópico .
fonte
java.nio.file.Path.moveTo()
No meu caso, parecia ser um objeto morto em meu próprio aplicativo, que mantinha um identificador para esse arquivo. Então, essa solução funcionou para mim:
Vantagem: é muito rápido, pois não há Thread.sleep () com um tempo codificado específico.
Desvantagem: esse limite de 20 é algum número codificado. Em todos os meus testes, i = 1 é suficiente. Mas, para ter certeza, deixei em 20.
fonte
Eu sei que isso parece um pouco hackeado, mas para o que estou precisando, parece que leitores e gravadores em buffer não têm problemas para criar os arquivos.
Funciona bem para pequenos arquivos de texto como parte de um analisador, apenas certifique-se de que oldName e newName sejam caminhos completos para os locais dos arquivos.
Cheers Kactus
fonte
O código a seguir NÃO é uma 'alternativa', mas funcionou de maneira confiável para mim em ambientes Windows e Linux:
fonte
No windows eu uso
Runtime.getRuntime().exec("cmd \\c ")
e, em seguida, uso a função de renomeação da linha de comando para realmente renomear arquivos. É muito mais flexível, por exemplo, se você quiser renomear a extensão de todos os arquivos txt em um diretório para bak, basta escrever no fluxo de saída:renomear * .txt * .bak
Eu sei que não é uma boa solução, mas aparentemente sempre funcionou para mim, muito melhor do que o suporte embutido Java.
fonte
Por que não....
funciona no nwindows 7, não faz nada se existingFile não existir, mas obviamente poderia ser melhor instrumentado para corrigir isso.
fonte
Eu tive uma questão semelhante. O arquivo foi copiado em vez de mover no Windows, mas funcionou bem no Linux. Corrigi o problema fechando o fileInputStream aberto antes de chamar renameTo (). Testado em Windows XP.
fonte
No meu caso, o erro estava no caminho do diretório pai. Talvez um bug, tive que usar a substring para obter um caminho correto.
fonte
Eu sei que é uma merda, mas uma alternativa é criar um script bat que produza algo simples como "SUCCESS" ou "ERROR", invoque-o, espere que seja executado e verifique seus resultados.
Runtime.getRuntime (). Exec ("cmd / c start test.bat");
Este tópico pode ser interessante. Verifique também a classe Process para saber como ler a saída do console de um processo diferente.
fonte
Você pode tentar o robocopy . Isso não é exatamente "renomear", mas é muito confiável.
fonte
Para mover / renomear um arquivo, você pode usar esta função:
Ele é definido em kernel32.dll.
fonte
O código acima é simples. Eu testei no windows 7 e funciona perfeitamente bem.
fonte