1. Introduction
La gestion des fichiers et du réseau est l’un des sujets les plus importants en programmation. Presque toute application moderne interagit d’une manière ou d’une autre avec Internet : elle télécharge des données, envoie des requêtes, reçoit des images ou des documents. Même un simple programme comme un client de chat ou un lecteur de musique manipule forcément le chargement de ressources.
Aujourd’hui, nous allons voir comment faire cela en Java, à l’aide de l’exemple le plus parlant et agréable à manipuler — les images. Pourquoi elles en particulier ?
- Visible immédiatement : Si tout a fonctionné, vous ouvrez simplement le fichier téléchargé et vous voyez l’image. C’est un résultat instantané et compréhensible.
- Compétence universelle : Une image n’est pas « juste une image », ce sont des données binaires, des « octets bruts ». En apprenant à les manipuler, vous pourrez télécharger n’importe quoi : documents, vidéos, musique, archives. Le principe est le même !
- Cas d’usage réels : La capacité à télécharger des ressources depuis le réseau est un fondement pour créer toute application moderne, des simples téléchargeurs de fonds d’écran aux systèmes complexes travaillant avec les API des réseaux sociaux.
Nous examinerons deux approches : le « service postal » rapide — via URL, et la « société de transport professionnelle » — via HttpClient avec contrôle des en‑têtes, des statuts et des délais d’attente.
2. Méthode la plus simple : la classe URL
En Java, la classe URL représente une adresse réseau. Elle permet d’ouvrir une connexion et d’obtenir un flux de données (type InputStream). Ce flux peut être manipulé comme un fichier : lire des octets, copier vers un autre flux, traiter comme du texte.
En essence, utiliser URL est le chemin le plus court du lien dans le navigateur au fichier sur le disque.
Premier exemple minimal
Supposons que nous ayons un lien vers une image :
URL url = new URL("https://example.com/image.jpg");
Files.copy(url.openStream(), Path.of("a.jpg"));
Deux lignes seulement. Que se passe‑t‑il ici ?
- Nous créons un objet URL en lui passant la chaîne contenant l’adresse de l’image.
- Nous appelons la méthode openStream(), qui ouvre une connexion réseau et renvoie un flux InputStream.
- Avec la méthode Files.copy, nous copions le contenu du flux dans le fichier "a.jpg".
Résultat : l’image provenant d’Internet est enregistrée dans notre dossier de travail.
Variante avec transferTo
Il existe une autre façon d’acheminer les données du flux vers un fichier :
InputStream in = new URL("https://example.com/image.jpg").openStream();
in.transferTo(Files.newOutputStream(Path.of("b.jpg")));
Ici, nous disons explicitement : prends le flux in et « transfère » toutes les données avec la méthode transferTo vers le flux qui écrit le fichier "b.jpg".
Le résultat sera le même : l’image se retrouvera sur le disque.
Points importants
Cette approche est très simple, mais elle a ses nuances. Tout d’abord, nous ne vérifions en rien ce qui arrive réellement depuis le lien. C’est peut‑être une image. Ou peut‑être une page HTML avec l’erreur 404. Dans les deux cas, le fichier sera enregistré. La différence ne sera visible que plus tard, lorsque vous tenterez de l’ouvrir dans une visionneuse d’images.
3. Méthode moderne : HttpClient
Depuis Java 11, une nouvelle API est entrée dans la bibliothèque standard — HttpClient. Elle permet d’effectuer des requêtes HTTP de façon moderne : travailler avec les méthodes GET, POST et autres, gérer les délais d’attente, surveiller les en‑têtes et les statuts, traiter les redirections.
Pour télécharger des images, c’est particulièrement utile : nous pouvons nous assurer que le fichier a bien été téléchargé avec succès et non une erreur.
Exemple minimal avec HttpClient
URI uri = URI.create("https://example.com/image.jpg"); // URI — version plus moderne de URL
HttpClient client = HttpClient.newHttpClient(); // Crée un objet HttpClient
HttpRequest request = HttpRequest.newBuilder(uri).build(); // Crée un objet "requête"
HttpResponse<byte[]> response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
Files.write(Path.of("c.jpg"), response.body());
Maintenant, étape par étape :
- Nous créons le client HttpClient.
- Nous construisons une requête HttpRequest vers l’adresse indiquée.
- Nous envoyons la requête et recevons la réponse sous forme de tableau d’octets : HttpResponse.BodyHandlers.ofByteArray().
- Nous écrivons ces octets dans un fichier avec Files.write — "c.jpg".
Résultat : la même image, mais cette fois nous disposons de plus d’informations sur la façon dont le serveur a répondu.
Vérification du statut de la réponse
L’objet response possède la méthode statusCode(). Avec elle, on peut s’assurer que le serveur a renvoyé une réponse réussie :
if (response.statusCode() == 200)
{
Files.write(Path.of("ok.jpg"), response.body());
}
else
{
System.out.println("Erreur : code " + response.statusCode());
}
Nous savons désormais que nous avons enregistré exactement ce que nous attendions, et non une page d’erreur.
Récupération des en‑têtes
Supposons que nous voulions vérifier le type de contenu :
String type = response.headers().firstValue("Content-Type").orElse("inconnu");
System.out.println("Type de contenu : " + type);
Si le serveur renvoie "image/png" ou "image/jpeg", c’est bien une image. Si c’est "text/html", c’est un signal d’alerte.
Délais d’attente
Pour éviter que le programme ne se bloque si le serveur met trop de temps à répondre, on peut définir une limite :
URI uri = URI.create("https://example.com/image.jpg");
HttpRequest req = HttpRequest.newBuilder(uri)
.timeout(Duration.ofSeconds(5))
.build();
Si le serveur ne répond pas en 5 secondes, la requête se terminera par une erreur.
Gestion des redirections
Parfois, les liens ne pointent pas directement vers le fichier mais d’abord vers une page de redirection. Pour activer le suivi automatique des redirections :
HttpClient client = HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.NORMAL)
.build();
4. Scénarios pratiques
Téléchargement de plusieurs images d’affilée
Il est souvent nécessaire de télécharger non pas une, mais des dizaines ou des centaines d’images. Par exemple, vous écrivez un programme qui enregistre des avatars d’utilisateurs ou des photos de produits. Avec HttpClient, cela se fait dans une boucle :
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());
}
}
Vérification de la taille du fichier
Il peut être utile de connaître le nombre d’octets dans l’image. Le serveur peut l’indiquer dans l’en‑tête "Content-Length" :
String length = response.headers().firstValue("Content-Length").orElse("?");
System.out.println("Taille : " + length + " octets");
Si l’en‑tête est absent, on peut toujours utiliser response.body().length.
Téléchargement et affichage d’une image dans le programme
Parfois, il faut non seulement télécharger l’image, mais aussi l’afficher immédiatement. Pour cela, on peut utiliser la bibliothèque javax.imageio.ImageIO :
InputStream in = new URL("https://example.com/pic.png").openStream();
BufferedImage img = ImageIO.read(in);
System.out.println("Largeur : " + img.getWidth() + ", hauteur : " + img.getHeight());
Ainsi, nous pouvons vérifier l’image directement en mémoire, sans même l’enregistrer sur le disque.
GO TO FULL VERSION