W3docs

Creación de archivos en Java

Crea archivos y directorios en Java con File.createNewFile, Files.createFile y Files.createDirectories.

"Crear un nuevo archivo vacío" y "crear este árbol de directorios" son dos de las operaciones más simples que ofrece el sistema de archivos, pero Java expone cuatro formas superpuestas de hacer cada una. Las diferencias importan: son la diferencia entre "falla si el archivo existe" y "sobreescribe silenciosamente", entre "mkdir" y "mkdir -p", entre un método heredado que devuelve un boolean y uno moderno que lanza una excepción.

Este capítulo cubre los cuatro métodos de creación:

  • File.createNewFile() — creación de archivos heredada.
  • File.mkdir() / File.mkdirs() — creación de directorios heredada.
  • Files.createFile(path) — creación moderna atómica "crear o fallar".
  • Files.createDirectory(path) / Files.createDirectories(path) — creación moderna de directorios.

Además de los helpers para archivos temporales (Files.createTempFile, Files.createTempDirectory) y los flags OpenOption que permiten a los escritores crear archivos de forma implícita.

File.createNewFile() — heredado, devuelve un 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

El contrato es verificación y creación atómica: el sistema operativo garantiza que ningún otro proceso puede crear la misma ruta entre la verificación de existencia y la creación. Eso convierte a createNewFile en un primitivo de bloqueo bajo algunos idioms heredados de "archivo PID": if (!f.createNewFile()) throw new IllegalStateException("already running");

Lo que no hace:

  • No crea directorios padre faltantes. new File("does/not/exist/file.txt").createNewFile() lanza IOException.
  • Devuelve false (no lanza excepción) cuando el archivo ya existe.

Si solo necesitas que el archivo exista al final de la llamada, el valor de retorno false es aceptable. Si necesitas que el archivo sea completamente nuevo (semántica de bloqueo), false es tu señal para tomar un camino diferente.

File.mkdir() y 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 devuelven boolean, ambos pierden información sobre por qué ocurrió un fallo. mkdir falla si falta un padre; mkdirs no. Ambos tienen éxito (devuelven true) solo si el directorio fue recién creado — si ya existe, devuelven false. Combinado con el problema de "no hay información del error", este es el tipo de API heredada que se envuelve en un helper:

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

El moderno Files.createDirectories(path) es el reemplazo en una sola línea.

Files.createFile(path) — moderno, lanza excepciones

Files.createFile es el equivalente en java.nio.file de File.createNewFile() con una diferencia importante: lanza excepciones en lugar de devolver un 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 es lo que capturas con catch si el resultado de existencia importa; NoSuchFileException es lo que capturas (o evitas con createDirectories) si el padre puede no estar presente. Los tipos de excepción son subclases específicas de IOException, por lo que un catch (IOException e) general sigue funcionando.

Puedes pasar argumentos FileAttribute para establecer permisos POSIX en el momento de la creación en Unix — el uso más común es asegurarse de que los archivos secretos (claves privadas, tokens) se creen con 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

(Esa llamada lanza UnsupportedOperationException en Windows, que no tiene modelo de permisos POSIX — protege con una verificación de plataforma si apuntas a ambos sistemas.)

Files.createDirectory versus Files.createDirectories

La misma diferencia que entre mkdir y mkdir -p, pero basada en excepciones:

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

createDirectory lanza FileAlreadyExistsException si el destino ya existe y no es un directorio; si ya es un directorio, también lanza (no es lo que sueles querer).

createDirectories es la opción más amigable: no hace nada si todos los directorios ya existen, y crea lo que falte en caso contrario. No lanza excepción si la ruta ya existe como directorio. Eso lo hace idempotente — seguro de llamar al inicio sin una verificación de exists().

Archivos y directorios temporales

Para pruebas, espacio de trabajo temporal y "necesito un lugar seguro donde poner esto por unos minutos", el JDK incluye Files.createTempFile y Files.createTempDirectory:

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

Ambos eligen un nombre único en el directorio temporal del sistema, ambos devuelven un Path a la nueva entrada, y ambos crean la entrada con permisos restrictivos en Unix. El prefijo y sufijo son sugerencias a las que el JDK agrega un valor único — no puedes elegir el nombre exacto (ese es el punto: otro llamador no puede predecirlo y sobreescribir el tuyo).

Los archivos temporales no se eliminan automáticamente. Debes:

  • Llamar a Files.deleteIfExists(path) cuando termines; o
  • Llamar a path.toFile().deleteOnExit() para programar una eliminación al apagar la JVM (anulado por kills forzados); o
  • Abrir el archivo con StandardOpenOption.DELETE_ON_CLOSE si solo lo necesitas mientras un stream está abierto.

Los escritores crean archivos de forma implícita

La mayor parte del tiempo no necesitas una llamada a "crear archivo" en absoluto — un escritor crea uno por ti. Files.newBufferedWriter, Files.write y Files.writeString todos aceptan varargs OpenOption... que deciden qué sucede cuando el archivo existe o no:

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 — crea si no existe, de lo contrario abre el existente.
  • CREATE_NEW — crea, lanza FileAlreadyExistsException si ya existe. La misma semántica que Files.createFile.
  • TRUNCATE_EXISTING — borra el contenido del archivo al abrirlo (el valor predeterminado para writeString cuando no se agrega contenido).
  • APPEND — escribe al final sin truncar.

El valor predeterminado de Files.writeString (sin opciones) es CREATE, WRITE, TRUNCATE_EXISTING — es decir, "crear o sobreescribir". Files.newBufferedWriter tiene el mismo comportamiento predeterminado. Si quieres semántica de append, debes indicarlo explícitamente.

Un ejemplo práctico: cada método de creación lado a lado

El programa a continuación construye un pequeño árbol desde cero bajo el directorio temporal del sistema usando ambas APIs y varias opciones de apertura. Cada paso imprime lo que cambió; el último bloque muestra qué sucede cuando vuelves a ejecutar una operación contra una ruta que ya existe.

java— editable, runs on the server

Lo que hay que destacar de la ejecución:

  • El primer legacy.createNewFile() devolvió true (creado); el segundo devolvió false (ya existía). El boolean no te dice qué ocurrió — tienes que recordar la convención.
  • deep.mkdirs() tuvo éxito la primera vez y devolvió false la segunda. Ese false es idéntico a "permiso denegado" o "padre faltante" — exactamente el problema de falta de información de error que Files resuelve.
  • Files.createFile sobre una ruta existente lanzó FileAlreadyExistsException. El tipo de excepción es específico, por lo que un manejador real puede distinguir "ya existe" de "permiso denegado" sin analizar cadenas de texto.
  • Files.createDirectories llamado dos veces seguidas no causó ningún daño la segunda vez. Esa es la propiedad que lo convierte en la elección correcta en el código de inicio: sin guardas, simplemente llámalo.
  • Files.writeString(log, "line 1\n") creó el archivo porque CREATE está en las opciones predeterminadas. Las llamadas segunda y tercera usaron APPEND explícitamente, y el archivo acumuló tres líneas. La cuarta llamada usó CREATE_NEW y se negó a sobreescribir. Los valores predeterminados están diseñados para el caso de "sobreescribir con nuevo contenido"; tienes que indicar explícitamente el modo append.
  • Files.createTempFile(root, "scratch-", ".tmp") produjo un nombre como scratch-1827392.tmp — tu prefijo y sufijo, más un fragmento único que la JVM elige para que dos llamadas concurrentes nunca colisionen.
  • La limpieza recorre root en orden inverso para que los archivos y directorios hijos desaparezcan antes que sus padres. Files.delete se niega a eliminar un directorio no vacío; ese orden es cómo se construye un rm -rf manual.

Qué viene después

Ya puedes crear archivos; el siguiente capítulo, Lectura de archivos en Java, los lee — primero con los helpers modernos en una línea (Files.readString, Files.readAllLines, Files.lines), luego con la pila de decoradores clásica FileReader / BufferedReader / Scanner para que el código más antiguo en los capítulos siguientes tenga una base.

Práctica

Práctica
Quieres una línea que cree un directorio junto con cualquier directorio padre faltante, y que **no haga nada** si el directorio ya existe. ¿Cuál es la llamada correcta?
Quieres una línea que cree un directorio junto con cualquier directorio padre faltante, y que **no haga nada** si el directorio ya existe. ¿Cuál es la llamada correcta?
Was this page helpful?