Existe uma maneira padrão e confiável de criar um diretório temporário dentro de um aplicativo Java? Há uma entrada no banco de dados de problemas do Java , que tem um pouco de código nos comentários, mas eu me pergunto se há uma solução padrão a ser encontrada em uma das bibliotecas comuns (Apache Commons etc.)?
364
temp.delete(); temp = new File(temp.getPath + ".d"); temp.mkdir(); ..., temp.delete();
.delete()
emkdir()
: Enquanto isso, um processo malicioso pode criar o diretório de destino (usando o nome do arquivo criado recentemente). VejaFiles.createTempDir()
uma alternativa.A biblioteca do Google Guava possui vários utilitários úteis. Uma nota aqui é a classe Arquivos . Possui vários métodos úteis, incluindo:
Isso faz exatamente o que você pediu em uma linha. Se você ler a documentação aqui, verá que a adaptação proposta
File.createTempFile("install", "dir")
geralmente apresenta vulnerabilidades de segurança.fonte
Se você precisa de um diretório temporário para testar e você estiver usando JUnit,
@Rule
juntamente comTemporaryFolder
resolve o seu problema:A partir da documentação :
Atualizar:
Se você estiver usando o JUnit Jupiter (versão 5.1.1 ou superior), terá a opção de usar o JUnit Pioneer, que é o JUnit 5 Extension Pack.
Copiado da documentação do projeto :
Mais informações no JavaDoc e no JavaDoc do TempDirectory
Gradle:
Maven:
Atualização 2:
A anotação @TempDir foi adicionada à versão do JUnit Jupiter 5.4.0 como um recurso experimental. Exemplo copiado do Guia do Usuário JUnit 5 :
fonte
O código escrito de forma ingênua para resolver esse problema sofre com as condições da corrida, incluindo várias das respostas aqui. Historicamente, você pode pensar cuidadosamente sobre as condições da corrida e escrevê-lo, ou pode usar uma biblioteca de terceiros como o Guava do Google (como sugeriu a resposta de Spina.) Ou pode escrever um código de buggy.
Mas a partir do JDK 7, há boas notícias! A própria biblioteca padrão Java agora oferece uma solução (não atrevida) adequada para esse problema. Você deseja java.nio.file.Files # createTempDirectory () . A partir da documentação :
Isso efetivamente resolve o relatório de erros embaraçosamente antigo no rastreador de erros da Sun, que solicitava exatamente essa função.
fonte
Este é o código fonte do arquivo Files.createTempDir () da biblioteca Guava. Não é tão complexo quanto você imagina:
Por padrão:
Veja aqui
fonte
Não use
deleteOnExit()
mesmo se você explicitamente excluí-lo mais tarde.O Google 'deleteonexit is evil' para mais informações, mas a essência do problema é:
deleteOnExit()
exclui apenas os encerramentos normais da JVM, não trava ou mata o processo da JVM.deleteOnExit()
exclui apenas no encerramento da JVM - não é bom para processos de servidor de longa execução porque:O pior de todos -
deleteOnExit()
consome memória para cada entrada de arquivo temporário. Se seu processo estiver em execução por meses ou criar muitos arquivos temporários em pouco tempo, você consome memória e nunca a libera até que a JVM seja encerrada.fonte
A partir do Java 1.7
createTempDirectory(prefix, attrs)
ecreateTempDirectory(dir, prefix, attrs)
estão incluídos nojava.nio.file.Files
Exemplo:
File tempDir = Files.createTempDirectory("foobar").toFile();
fonte
Isto é o que eu decidi fazer pelo meu próprio código:
fonte
Bem, "createTempFile" na verdade cria o arquivo. Então, por que não excluí-lo primeiro e depois fazer o mkdir?
fonte
Este código deve funcionar razoavelmente bem:
fonte
Conforme discutido nesta RFE e seus comentários, você pode ligar
tempDir.delete()
primeiro. Ou você pode usarSystem.getProperty("java.io.tmpdir")
e criar um diretório lá. De qualquer forma, lembre-se de ligartempDir.deleteOnExit()
ou o arquivo não será excluído depois que você terminar.fonte
Apenas para conclusão, este é o código da biblioteca do google goiaba. Não é meu código, mas acho que é valioso mostrá-lo aqui neste tópico.
fonte
Eu tenho o mesmo problema, então essa é apenas mais uma resposta para aqueles que estão interessados, e é semelhante a um dos itens acima:
E para o meu aplicativo, decidi adicionar uma opção para limpar a temperatura na saída, adicionando um gancho de desligamento:
O método exclui todos os subdiretórios e arquivos antes de excluir o temp , sem usar o callstack (que é totalmente opcional e você pode fazê-lo com recursão neste momento), mas quero estar do lado seguro.
fonte
Como você pode ver nas outras respostas, nenhuma abordagem padrão surgiu. Portanto, você já mencionou o Apache Commons, proponho a seguinte abordagem usando o FileUtils do Apache Commons IO :
Isso é preferido, pois o apache comunica a biblioteca que mais se aproxima do "padrão" solicitado e funciona com o JDK 7 e versões mais antigas. Isso também retorna uma instância de arquivo "antiga" (que é baseada em fluxo) e não uma instância de caminho "nova" (que é baseada em buffer e seria o resultado do método getTemporaryDirectory () do JDK7) -> Portanto, ele retorna o que a maioria das pessoas precisa quando eles querem criar um diretório temporário.
fonte
Gosto das várias tentativas de criar um nome único, mas mesmo essa solução não descarta uma condição de corrida. Outro processo pode ocorrer após o teste
exists()
e aif(newTempDir.mkdirs())
invocação do método. Não tenho idéia de como tornar isso completamente seguro sem recorrer ao código nativo, que eu presumo é o que está escondido dentro deleFile.createTempFile()
.fonte
Antes do Java 7, você também podia:
fonte
Tente este pequeno exemplo:
Código:
Importações:
java.io.IOException
java.nio.file.Files
java.nio.file.Path
Saída do console na máquina Windows:
C: \ Users \ userName \ AppData \ Local \ Temp \ tmpDir2908538301081367877
Comentário:
Files.createTempDirectory gera ID exclusivo automaticamente - 2908538301081367877.
Nota:
Leia o seguinte para excluir diretórios recursivamente:
Exclua diretórios recursivamente em Java
fonte
Usar
File#createTempFile
edelete
criar um nome exclusivo para o diretório parece ok. Você deve adicionar aShutdownHook
para excluir o diretório (recursivamente) no encerramento da JVM.fonte