CodeGym /Cursos /JAVA 25 SELF /Descargamos imágenes de Internet

Descargamos imágenes de Internet

JAVA 25 SELF
Nivel 12 , Lección 4
Disponible

1. Introducción

Trabajar con archivos y redes es uno de los temas más importantes en programación. Casi cualquier aplicación moderna interactúa de una forma u otra con Internet: descarga datos, envía solicitudes, recibe imágenes o documentos. Incluso un programa sencillo como un cliente de chat o un reproductor de música necesariamente trata con la descarga de recursos.

Hoy veremos cómo hacerlo en Java con el ejemplo más visual y agradable de manejar: las imágenes. ¿Por qué precisamente imágenes?

  • Se ve al instante: Si todo ha funcionado, simplemente abres el archivo descargado y ves la imagen. Es un resultado inmediato y claro.
  • Una habilidad universal: Las imágenes no son solo imágenes, son datos binarios, «bytes en bruto». Una vez aprendas a trabajar con ellos, podrás descargar lo que sea: documentos, vídeos, música, archivos. ¡El principio es el mismo!
  • Casos reales: Saber descargar recursos de la red es la base para crear cualquier aplicación moderna, desde simples descargadores de fondos de pantalla hasta sistemas complejos que trabajan con API de redes sociales.

Lo veremos con dos enfoques: el «servicio postal» rápido — mediante URL, y la «empresa de transporte profesional» — mediante HttpClient, con control de cabeceras, estados y tiempos de espera.

2. El método más simple: la clase URL

En Java existe la clase URL, que representa una dirección de red. Permite abrir una conexión y obtener un flujo de datos (tipo InputStream). Con este flujo se puede trabajar igual que con un archivo: leer bytes, copiar a otro flujo, procesar como texto.

En esencia, usar URL es el camino más corto desde un enlace en el navegador hasta un archivo en el disco.

Primer ejemplo mínimo

Supongamos que tenemos un enlace a una imagen:

URL url = new URL("https://example.com/image.jpg");
Files.copy(url.openStream(), Path.of("a.jpg"));

Solo dos líneas. ¿Qué está pasando aquí?

  1. Creamos un objeto URL pasando la cadena con la dirección de la imagen.
  2. Llamamos al método openStream(), que abre la conexión de red y devuelve un flujo InputStream.
  3. Con el método Files.copy copiamos el contenido del flujo al archivo "a.jpg".

Resultado: la imagen de Internet se guarda en nuestra carpeta de trabajo.

Variante con transferTo

Hay otra forma de enviar los datos del flujo al archivo:

InputStream in = new URL("https://example.com/image.jpg").openStream();
in.transferTo(Files.newOutputStream(Path.of("b.jpg")));

Aquí decimos explícitamente: toma el flujo in y «transfiere» todos los datos con el método transferTo al flujo que escribe el archivo "b.jpg".

El resultado será el mismo: la imagen terminará en el disco.

Detalles importantes

Este enfoque es muy simple, pero tiene matices. Para empezar, no comprobamos qué es exactamente lo que llegó por el enlace. Puede que sea una imagen. O puede que sea una página HTML con un error 404. En ambos casos el archivo se guardará. La diferencia solo se notará después, cuando intentes abrirlo en el visor de imágenes.

3. Método moderno: HttpClient

A partir de Java 11, la biblioteca estándar incorpora una nueva herramienta — HttpClient. Permite realizar solicitudes HTTP de forma moderna: trabajar con métodos GET, POST y otros, gestionar tiempos de espera, inspeccionar cabeceras y códigos de estado, y manejar redirecciones.

Para descargar imágenes esto es especialmente útil: podemos asegurarnos de que el archivo se ha descargado correctamente y no hemos recibido un error.

Ejemplo mínimo con HttpClient

URI uri = URI.create("https://example.com/image.jpg");   // URI: versión más moderna de URL

HttpClient client = HttpClient.newHttpClient();          // Creamos un objeto HttpClient
HttpRequest request = HttpRequest.newBuilder(uri).build(); // Creamos el objeto "solicitud"

HttpResponse<byte[]> response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
Files.write(Path.of("c.jpg"), response.body());

Ahora, paso a paso:

  1. Creamos el cliente HttpClient.
  2. Construimos la solicitud HttpRequest para la dirección indicada.
  3. Enviamos la solicitud y obtenemos la respuesta como un array de bytes: HttpResponse.BodyHandlers.ofByteArray().
  4. Escribimos esos bytes en un archivo con Files.write"c.jpg".

Resultado: la misma imagen, pero ahora tenemos más información sobre cómo respondió el servidor.

Comprobación del estado de la respuesta

El objeto response tiene el método statusCode(). Con él podemos asegurarnos de que el servidor devolvió una respuesta satisfactoria:

if (response.statusCode() == 200)
{
    Files.write(Path.of("ok.jpg"), response.body());
}
else
{
    System.out.println("Error: código " + response.statusCode());
}

Ahora sabemos con certeza que hemos guardado exactamente lo que esperábamos y no una página de error.

Obtener cabeceras

Supongamos que queremos comprobar el tipo de contenido:

String type = response.headers().firstValue("Content-Type").orElse("desconocido");
System.out.println("Tipo de contenido: " + type);

Si el servidor devolvió "image/png" o "image/jpeg", entonces es realmente una imagen. Si llegó "text/html", es una señal de alarma.

Tiempos de espera

Para que el programa no se quede colgado si el servidor tarda en responder, podemos establecer un límite:

URI uri = URI.create("https://example.com/image.jpg");
HttpRequest req = HttpRequest.newBuilder(uri)
    .timeout(Duration.ofSeconds(5))
    .build();

Si el servidor no responde en 5 segundos, la solicitud terminará con un error.

Gestión de redirecciones

A veces los enlaces no llevan directamente al archivo, sino primero a una página de redirección. Para activar el seguimiento automático de redirecciones, se puede hacer así:

HttpClient client = HttpClient.newBuilder()
    .followRedirects(HttpClient.Redirect.NORMAL)
    .build();

4. Escenarios prácticos

Descarga de varias imágenes seguidas

A menudo hay que descargar no una, sino decenas o cientos de imágenes. Por ejemplo, si escribes un programa que guarda avatares de usuarios o fotos de productos. Con HttpClient esto se hace con un bucle:

var client = HttpClient.newHttpClient();

String[] urls = {
    "https://example.com/img1.jpg",
    "https://example.com/img2.jpg"
};

for (int i = 0; i < urls.length; i++)
{
    var uri = URI.create(urls[i]);
    var request = HttpRequest.newBuilder(uri).build();
    var response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
    if (response.statusCode() == 200) {
        Files.write(Path.of("img" + i + ".jpg"), response.body());
    }
}

Comprobar el tamaño del archivo

A veces es útil saber cuántos bytes tiene la imagen. El servidor puede indicarlo en la cabecera "Content-Length":

String length = response.headers().firstValue("Content-Length").orElse("?");
System.out.println("Tamaño: " + length + " bytes");

Si la cabecera no está, siempre puedes simplemente usar response.body().length.

Descargar y mostrar la imagen en el programa

A veces no solo hay que descargar la imagen, sino mostrarla de inmediato. Para ello se puede usar la biblioteca javax.imageio.ImageIO:

InputStream in = new URL("https://example.com/pic.png").openStream();
BufferedImage img = ImageIO.read(in);
System.out.println("Ancho: " + img.getWidth() + ", alto: " + img.getHeight());

Así podemos verificar la imagen directamente en memoria, sin siquiera guardarla en el disco.

Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION