W3docs

Criando Arquivos em Java

Crie arquivos e diretórios em Java com File.createNewFile, Files.createFile e Files.createDirectories.

"Criar um novo arquivo vazio" e "criar esta árvore de diretórios" são duas das operações mais simples que o sistema de arquivos oferece, mas o Java expõe quatro maneiras sobrepostas de fazer cada uma. As diferenças importam — é a diferença entre "falha se o arquivo existe" e "sobrescreve silenciosamente," entre "mkdir" e "mkdir -p," entre um método legado que retorna boolean e um moderno que lança exceção.

Este capítulo cobre os quatro criadores:

  • File.createNewFile() — criação legada de arquivo.
  • File.mkdir() / File.mkdirs() — criação legada de diretório.
  • Files.createFile(path) — "criar ou falhar" atômico moderno.
  • Files.createDirectory(path) / Files.createDirectories(path) — criação moderna de diretório.

Além dos auxiliares de arquivo temporário (Files.createTempFile, Files.createTempDirectory) e os flags OpenOption que permitem que escritores criem arquivos implicitamente.

File.createNewFile() — legado, retorna um boolean

File f = new File("data/users.txt");
boolean created = f.createNewFile();      // true if it actually created the file
                                          // false if it already existed
                                          // throws IOException if the parent dir is missing

O contrato é verificação e criação atômica: o SO garante que nenhum outro processo pode criar o mesmo caminho entre a verificação de existência e a criação. Isso torna createNewFile um bloqueio primitivo em alguns idiomas legados de "arquivo PID" — if (!f.createNewFile()) throw new IllegalStateException("already running");

O que ele não faz:

  • Ele não cria diretórios pai ausentes. new File("does/not/exist/file.txt").createNewFile() lança IOException.
  • Ele retorna false (não lança) quando o arquivo já existe.

Se você só precisa que o arquivo exista ao final da chamada, o valor de retorno false está correto. Se você precisa que o arquivo seja totalmente novo (semântica de bloqueio), false é o sinal para tomar um caminho diferente.

File.mkdir() e File.mkdirs()

new File("logs").mkdir();           // creates "logs" — fails if "." has no perms or parent missing
new File("a/b/c").mkdirs();          // creates "a", "a/b", and "a/b/c" — like `mkdir -p`

Ambos retornam boolean, ambos perdem informação sobre por que uma falha aconteceu. mkdir falha se um pai estiver ausente; mkdirs não. Ambos têm sucesso (retornam true) apenas se o diretório foi recém-criado — se já existe, retornam false. Combinado com o problema de "sem informação de erro," esta é a API legada que acaba sendo encapsulada em um auxiliar:

File dir = new File("data");
if (!dir.exists() && !dir.mkdirs()) throw new IOException("cannot create " + dir);

O moderno Files.createDirectories(path) é o substituto de uma linha.

Files.createFile(path) — moderno, lança exceção

Files.createFile é o par java.nio.file de File.createNewFile() com uma diferença importante: ele lança exceção em vez de retornar um boolean.

Path p = Path.of("data/users.txt");
Files.createFile(p);                          // creates an empty regular file
                                              // throws FileAlreadyExistsException if it exists
                                              // throws NoSuchFileException if the parent is missing

FileAlreadyExistsException é o que você captura com catch se o resultado de existência importa; NoSuchFileException é o que você captura (ou previne com createDirectories) se o pai pode não estar lá. Os tipos de exceção são subclasses específicas de IOException, então um catch (IOException e) genérico ainda funciona.

Você pode passar argumentos FileAttribute para definir permissões POSIX no momento da criação no Unix — o uso mais comum é garantir que arquivos secretos (chaves privadas, tokens) sejam criados com 0600:

import static java.nio.file.attribute.PosixFilePermissions.*;
var attr = asFileAttribute(fromString("rw-------"));
Files.createFile(Path.of("/tmp/secret"), attr);   // born with 0600 permissions, atomically

(Essa chamada lança UnsupportedOperationException no Windows, que não possui modelo de permissão POSIX — proteja com uma verificação de plataforma se você tiver como alvo ambos.)

Files.createDirectory versus Files.createDirectories

A mesma diferença que mkdir versus mkdir -p, apenas baseada em exceção:

Files.createDirectory(Path.of("logs"));          // one level deep; parent must exist
Files.createDirectories(Path.of("a/b/c"));        // creates every missing ancestor

createDirectory lança FileAlreadyExistsException se o alvo já existe e não é um diretório; se já é um diretório, também lança (não é o que você geralmente quer).

createDirectories é a escolha mais amigável: não faz nada se todos os diretórios já estiverem lá, e cria o que estiver faltando caso contrário. Ele não lança se o caminho já existe como diretório. Isso o torna idempotente — seguro de chamar na inicialização sem uma verificação exists().

Arquivos e diretórios temporários

Para testes, espaço de trabalho e "preciso de um lugar seguro para colocar isso por alguns minutos," o JDK fornece Files.createTempFile e Files.createTempDirectory:

Path scratch = Files.createTempFile("session-", ".log");          // /tmp/session-3829387.log
Path workdir = Files.createTempDirectory("export-");               // /tmp/export-1827392

Ambos escolhem um nome único no diretório temporário do sistema, ambos retornam um Path para a nova entrada, e ambos criam a entrada com permissões restritivas no Unix. O prefixo e o sufixo são dicas às quais o JDK acrescenta um valor único — você não pode escolher o nome exato (esse é o ponto: outro chamador não pode prevê-lo e sobrescrever o seu).

Arquivos temporários não são excluídos automaticamente. Você pode:

  • Chamar Files.deleteIfExists(path) quando terminar; ou
  • Chamar path.toFile().deleteOnExit() para agendar uma exclusão no encerramento da JVM (cancelado por finalizações forçadas); ou
  • Abrir o arquivo com StandardOpenOption.DELETE_ON_CLOSE se você só precisar dele enquanto um stream estiver aberto.

Escritores criam arquivos implicitamente

Na maioria das vezes você não precisa de uma chamada de "criar arquivo" — um escritor cria um para você. Files.newBufferedWriter, Files.write e Files.writeString aceitam varargs OpenOption... que decidem o que acontece quando o arquivo existe ou não:

import static java.nio.file.StandardOpenOption.*;
Files.writeString(path, "hello\n", CREATE, WRITE, TRUNCATE_EXISTING);
Files.writeString(path, "more\n",  CREATE, WRITE, APPEND);
Files.writeString(path, "new\n",   CREATE_NEW);     // fails if file exists
  • CREATE — criar se ausente, caso contrário abrir o existente.
  • CREATE_NEW — criar, lançar FileAlreadyExistsException se existir. A mesma semântica que Files.createFile.
  • TRUNCATE_EXISTING — limpar o conteúdo do arquivo ao abrir (o padrão para writeString quando não é append).
  • APPEND — escrever no final sem truncar.

O padrão para Files.writeString (sem opções) é CREATE, WRITE, TRUNCATE_EXISTING — ou seja, "criar ou sobrescrever." Files.newBufferedWriter tem o mesmo padrão. Se você quer semântica de append, deve especificá-la explicitamente.

Um exemplo prático: cada criador lado a lado

O programa abaixo constrói uma pequena árvore do zero no diretório temporário do sistema usando ambas as APIs e várias opções abertas. Cada passo imprime o que mudou; o último bloco mostra o que acontece quando você re-executa uma operação em um caminho que já existe.

java— editable, runs on the server

O que observar na execução:

  • O primeiro legacy.createNewFile() retornou true (criado); o segundo retornou false (já existia). O boolean não diz o que aconteceu — você tem que lembrar a convenção.
  • deep.mkdirs() teve sucesso uma vez e retornou false na segunda vez. Esse false parece idêntico a "permissão negada" ou "pai ausente" — exatamente o problema de informação de erro faltante que Files resolve.
  • Files.createFile em um caminho existente lançou FileAlreadyExistsException. O tipo de exceção é específico, então um handler real pode distinguir "já existe" de "permissão negada" sem analisar strings.
  • Files.createDirectories chamado duas vezes seguidas não fez nada prejudicial na segunda vez. Essa é a propriedade que o torna a escolha certa em código de inicialização: sem guarda, apenas chame-o.
  • Files.writeString(log, "line 1\n") criou o arquivo porque CREATE está nas opções padrão. A segunda e terceira chamadas usaram APPEND explicitamente, e o arquivo acumulou três linhas. A quarta chamada usou CREATE_NEW e recusou sobrescrever. Os padrões são projetados para o caso de "sobrescrever com novo conteúdo"; você opta pelo append.
  • Files.createTempFile(root, "scratch-", ".tmp") produziu um nome como scratch-1827392.tmp — seu prefixo e sufixo, mais um trecho único que a JVM escolhe para que duas chamadas concorrentes nunca colidam.
  • A limpeza percorre root em ordem inversa para que arquivos e diretórios filhos desapareçam antes de seus pais. Files.delete recusa excluir um diretório não vazio; essa ordenação é como um rm -rf manual é construído.

O que vem a seguir

Você pode criar arquivos; o próximo capítulo, Lendo Arquivos em Java, os lê — primeiro com os one-liners modernos (Files.readString, Files.readAllLines, Files.lines), depois com a pilha clássica de decoradores FileReader / BufferedReader / Scanner para que o código mais antigo nos próximos capítulos tenha uma base.

Prática

Prática
Você quer um one-liner que crie um diretório mais quaisquer diretórios pai ausentes, e **não faça nada** se o diretório já existir. Qual chamada é essa?
Você quer um one-liner que crie um diretório mais quaisquer diretórios pai ausentes, e **não faça nada** se o diretório já existir. Qual chamada é essa?
Was this page helpful?