CodeGym /Cursos /JAVA 25 SELF /Lectura y escritura de archivos: operaciones básicas

Lectura y escritura de archivos: operaciones básicas

JAVA 25 SELF
Nivel 35, Lección 2
Disponible

1. Lectura completa de un archivo

Lectura de todos los bytes

A veces necesitas extraer de un archivo todo su contenido de una sola vez —tal cual, sin análisis—, ya sea una imagen, un archivo comprimido o algún formato binario. Para esto, Java tiene el método Files.readAllBytes(path). Devuelve un array de bytes (byte[]), es decir, los datos en bruto del archivo, que luego puedes usar como quieras.

import java.nio.file.*;

public class ReadBytesExample {
    public static void main(String[] args) throws Exception {
        Path path = Paths.get("example.txt");
        byte[] allBytes = Files.readAllBytes(path);
        System.out.println("Longitud del archivo en bytes: " + allBytes.length);
    }
}

Nota: Si el archivo es grande (gigabytes), este enfoque puede provocar problemas de memoria, ya que todo el contenido se carga de inmediato en la RAM.

Lectura de todas las líneas

Para archivos de texto hay una forma más cómoda: Files.readAllLines(path). Devuelve una lista de líneas (List<String>), donde cada elemento es una línea del archivo (los separadores de línea se tienen en cuenta automáticamente).

import java.nio.file.*;
import java.util.List;

public class ReadLinesExample {
    public static void main(String[] args) throws Exception {
        Path path = Paths.get("example.txt");
        List<String> lines = Files.readAllLines(path);

        for (String line : lines) {
            System.out.println(line);
        }
    }
}

Importante: Por defecto se usa la codificación del sistema. Si quieres especificar la codificación explícitamente (por ejemplo, UTF-8), utiliza la versión sobrecargada del método:

List<String> lines = Files.readAllLines(path, java.nio.charset.StandardCharsets.UTF_8);

Ejemplo: leemos un archivo y lo mostramos en pantalla

Vamos a añadir esto a nuestra miniaplicación (por ejemplo, «bloc de notas» o «lista de tareas»):

import java.nio.file.*;
import java.util.List;

public class TodoReader {
    public static void main(String[] args) throws Exception {
        Path todoPath = Paths.get("todo.txt");
        if (Files.exists(todoPath)) {
            List<String> tasks = Files.readAllLines(todoPath);
            System.out.println("Tus tareas para hoy:");
            for (String task : tasks) {
                System.out.println("- " + task);
            }
        } else {
            System.out.println("No se encontró el archivo todo.txt. ¡Crea una lista de tareas!");
        }
    }
}

2. Escritura en un archivo

Escritura de un array de bytes

Si dispones de un array de bytes (por ejemplo, el resultado de una serialización, una imagen, audio), utiliza Files.write(path, bytes). Este método crea el archivo si no existe o sobrescribe el existente.

import java.nio.file.*;

public class WriteBytesExample {
    public static void main(String[] args) throws Exception {
        Path path = Paths.get("output.bin");
        byte[] data = {1, 2, 3, 4, 5};
        Files.write(path, data);
        System.out.println("Bytes escritos en el archivo output.bin");
    }
}

Escritura de una lista de líneas

Para archivos de texto es más cómodo usar una lista de líneas: cada línea se escribirá por separado, con salto de línea.

import java.nio.file.*;
import java.util.Arrays;
import java.util.List;

public class WriteLinesExample {
    public static void main(String[] args) throws Exception {
        Path path = Paths.get("todo.txt");
        List<String> tasks = Arrays.asList(
            "Comprar leche",
            "Llamar a la abuela",
            "Hacer los deberes de Java"
        );
        Files.write(path, tasks);
        System.out.println("La lista de tareas se ha escrito en todo.txt");
    }
}

Atención: ¡Por defecto el archivo se sobrescribe! Si ya existía, las tareas antiguas desaparecerán. (Cómo no perder lo anterior — lo contaremos un poco más adelante).

Escritura de una cadena en un archivo

Si quieres escribir una sola cadena, crea una lista con una única línea o utiliza Files.write(path, string.getBytes()):

import java.nio.file.*;

public class WriteStringExample {
    public static void main(String[] args) throws Exception {
        Path path = Paths.get("hello.txt");
        String message = "¡Hola, Java!";
        Files.write(path, message.getBytes());
        System.out.println("La cadena se ha escrito en hello.txt");
    }
}

Especificar explícitamente la codificación

Para evitar «caracteres raros» al trabajar con texto en ruso (y no solo), indica siempre la codificación:

import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.List;

public class WriteLinesUtf8Example {
    public static void main(String[] args) throws Exception {
        Path path = Paths.get("hello.txt");
        List<String> lines = List.of("¡Hola, mundo!", "Esto es Java.");
        Files.write(path, lines, StandardCharsets.UTF_8);
    }
}

3. Manejo de errores

Al trabajar con archivos, Java puede lanzar la excepción IOException. Es una señal general de que «algo ha ido mal» a nivel de entrada/salida. Las causas pueden ser muchas: el archivo no existe, no hay permisos suficientes, el disco está lleno u ocupado, e incluso que alguien desconecte el pendrive en el peor momento.

Por eso, los métodos de lectura y escritura de archivos siempre requieren que estemos preparados para manejar estas situaciones. Se hace mediante try-catch:

import java.nio.file.*;
import java.util.List;
import java.io.IOException;

public class SafeReadExample {
    public static void main(String[] args) {
        Path path = Paths.get("todo.txt");
        try {
            List<String> lines = Files.readAllLines(path);
            System.out.println("Contenido del archivo:");
            for (String line : lines) {
                System.out.println(line);
            }
        } catch (IOException ex) {
            System.out.println("Error al leer el archivo: " + ex.getMessage());
        }
    }
}

¿Para qué sirve todo esto?

try-catch convierte un posible fallo de la aplicación en una situación controlada. Si el archivo no existe, se lo comunicamos al usuario con calma. Si el sistema no concede acceso, señalamos el problema. Y si el disco desaparece en mitad de la operación, el programa no caerá con un stack trace horrible, sino que al menos avisará con un mensaje comprensible. En otras palabras: IOException no es un enemigo, sino la forma que tiene Java de decirnos: «eh, aquí fuera algo ha fallado; piensa qué hacer a continuación».

4. Ejemplos prácticos

Leer un archivo y mostrar su contenido

import java.nio.file.*;
import java.util.List;
import java.io.IOException;

public class PrintFileExample {
    public static void main(String[] args) {
        Path path = Paths.get("notes.txt");
        try {
            if (!Files.exists(path)) {
                System.out.println("No se encontró el archivo notes.txt.");
                return;
            }
            List<String> lines = Files.readAllLines(path, java.nio.charset.StandardCharsets.UTF_8);
            System.out.println("Contenido del archivo notes.txt:");
            for (String line : lines) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("Error al leer el archivo: " + e.getMessage());
        }
    }
}

Escribir una cadena en un archivo nuevo

import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.io.IOException;

public class WriteFileExample {
    public static void main(String[] args) {
        Path path = Paths.get("greeting.txt");
        String content = "¡Bienvenido al mundo de Java IO!";
        try {
            Files.write(path, content.getBytes(StandardCharsets.UTF_8));
            System.out.println("La cadena se ha escrito en el archivo greeting.txt");
        } catch (IOException e) {
            System.out.println("Error al escribir el archivo: " + e.getMessage());
        }
    }
}

Escribir una lista de líneas en un archivo

import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.io.IOException;

public class WriteListExample {
    public static void main(String[] args) {
        Path path = Paths.get("shopping.txt");
        List<String> items = List.of("Pan", "Leche", "Queso");
        try {
            Files.write(path, items, StandardCharsets.UTF_8);
            System.out.println("La lista de la compra se ha escrito en shopping.txt");
        } catch (IOException e) {
            System.out.println("Error al escribir el archivo: " + e.getMessage());
        }
    }
}

5. Un apunte sobre flujos

Los métodos Files.readAllBytes, Files.readAllLines, Files.write son «todo de golpe»: o bien todo el archivo en memoria, o bien todo el contenido directamente al disco. Para archivos pequeños esto es cómodo, pero para archivos grandes no tanto (puedes obtener OutOfMemoryError o simplemente «quedarte colgado» leyendo logs de gigabytes).

Para trabajar con archivos grandes o para leer línea a línea se usan flujos:

  • Para texto: BufferedReader, BufferedWriter
  • Para bytes: InputStream, OutputStream

Hablaremos de los flujos con más detalle en próximas lecciones, pero aquí tienes un pequeño adelanto:

import java.nio.file.*;
import java.io.*;

public class BufferedReaderExample {
    public static void main(String[] args) {
        Path path = Paths.get("bigfile.txt");
        try (BufferedReader reader = Files.newBufferedReader(path)) {
            String line;
            while ((line = reader.readLine()) != null) {
                // Procesamos la línea
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("Error al leer el archivo: " + e.getMessage());
        }
    }
}

6. Detalles útiles

  • Sobrescritura del archivo: Todos los métodos de Files.write sobrescriben el archivo por defecto. Si necesitas añadir al final, utiliza opciones adicionales (hablaremos de ello en la próxima lección).
  • Codificación: Indica siempre la codificación explícitamente si trabajas con texto no ASCII. Te evitará «caracteres raros» en la salida. Una buena opción es StandardCharsets.UTF_8.
  • Rutas: Usa Paths.get(...) para ser multiplataforma. Nunca codifiques a mano las barras (/ o \).
  • Nombres de archivo: No uses en el nombre caracteres prohibidos (?, *, :, <, >, |, etc.), especialmente si tu código debe funcionar en Windows.

7. Errores típicos al leer y escribir archivos

Error n.º 1: no se maneja IOException. Muy a menudo, quienes empiezan escriben Files.readAllLines(path) sin try-catch, y ante el primer problema (archivo no encontrado, sin permisos, disco dañado) el programa se cae. ¡Maneja siempre las excepciones!

Error n.º 2: trabajar con archivos grandes mediante readAllBytes/readAllLines. Si el archivo pesa cientos de megabytes o gigabytes, intentar cargarlo entero puede «matar» tu programa. Para esos casos usa flujos (BufferedReader).

Error n.º 3: no especificar la codificación al escribir/leer texto. Si no indicas la codificación, en distintos equipos y SO el resultado puede variar. El problema aparece a menudo con alfabetos no latinos. Usa StandardCharsets.UTF_8 o la codificación que necesites de forma explícita.

Error n.º 4: esperar que File/Path sea el propio archivo. La clase File o Path es solo un «enlace» al archivo, no el archivo en sí. Al crear el objeto no creas el archivo en el disco. Para crear el archivo usa los métodos Files.createFile, Files.write, etc.

Error n.º 5: no cerrar el flujo (si usas flujos). Si usas flujos manualmente (por ejemplo, BufferedReader), ciérralos siempre (mejor mediante try-with-resources). De lo contrario, el archivo puede quedar bloqueado y no estar disponible para otros programas.

1
Tarea
JAVA 25 SELF, nivel 35, lección 2
Bloqueada
¿Cuánto espacio ocupa tu documento "secreto"? 📜
¿Cuánto espacio ocupa tu documento "secreto"? 📜
1
Tarea
JAVA 25 SELF, nivel 35, lección 2
Bloqueada
Visualización del registro de eventos del sistema 💻
Visualización del registro de eventos del sistema 💻
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION