CodeGym /Kursy /JAVA 25 SELF /Pobieranie obrazów z internetu

Pobieranie obrazów z internetu

JAVA 25 SELF
Poziom 12 , Lekcja 4
Dostępny

1. Wprowadzenie

Praca z plikami i siecią to jeden z najważniejszych tematów w programowaniu. Niemal każda nowoczesna aplikacja w taki czy inny sposób współpracuje z internetem: pobiera dane, wysyła żądania, odbiera obrazy lub dokumenty. Nawet prosty program, taki jak klient czatu czy odtwarzacz muzyki, ma do czynienia z pobieraniem zasobów.

Dziś wyjaśnimy, jak to robić w Javie, na przykładzie najbardziej obrazowego i przyjemnego ładunku — obrazów. Dlaczego właśnie one?

  • Widać od razu: Jeśli wszystko zadziałało, po prostu otwierasz pobrany plik i widzisz obraz. To natychmiastowy i zrozumiały rezultat.
  • Uniwersalna umiejętność: Obrazy to nie tylko obrazki, ale dane binarne, „surowe bajty”. Gdy nauczysz się z nimi pracować, będziesz mógł pobierać cokolwiek: dokumenty, wideo, muzykę, archiwa. Zasada jest ta sama!
  • Realne zadania: Umiejętność pobierania zasobów z sieci to fundament tworzenia każdej nowoczesnej aplikacji — od prostych pobieraczy tapet po złożone systemy współpracujące z API serwisów społecznościowych.

Zastosujemy dwa podejścia: szybka „poczta” — przez URL, oraz „profesjonalna firma transportowa” — przez HttpClient z kontrolą nagłówków, statusów i limitów czasu.

2. Najprostszy sposób: klasa URL

W Javie istnieje klasa URL, która reprezentuje adres sieciowy. Pozwala otworzyć połączenie i uzyskać strumień danych (typ InputStream). Ze strumieniem można pracować tak jak z plikiem: czytać bajty, kopiować do innego strumienia, przetwarzać jako tekst.

W istocie użycie URL to najkrótsza droga od linku w przeglądarce do pliku na dysku.

Pierwszy minimalny przykład

Załóżmy, że mamy link do obrazu:

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

Tylko dwie linijki. Co tu się dzieje?

  1. Tworzymy obiekt URL, przekazując mu łańcuch z adresem obrazu.
  2. Wywołujemy metodę openStream(), która otwiera połączenie sieciowe i zwraca strumień InputStream.
  3. Za pomocą metody Files.copy kopiujemy zawartość strumienia do pliku "a.jpg".

Efekt: obraz z internetu zostaje zapisany w naszym katalogu roboczym.

Wariant z transferTo

Jest jeszcze jeden sposób przekazania danych ze strumienia do pliku:

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

Tutaj mówimy wprost: weź strumień in i „przepompuj” wszystkie dane metodą transferTo do strumienia, który zapisuje plik "b.jpg".

Rezultat będzie taki sam: obraz trafi na dysk.

Ważne szczegóły

Takie podejście jest bardzo proste, ale ma niuanse. Po pierwsze, w ogóle nie sprawdzamy, co dokładnie przyszło pod danym linkiem. Może to być obraz. A może — strona HTML z błędem 404. W obu przypadkach plik zostanie zapisany. Różnica wyjdzie na jaw dopiero później, gdy spróbujesz otworzyć go w przeglądarce obrazów.

3. Nowoczesny sposób: HttpClient

Począwszy od Javy 11 do biblioteki standardowej trafiło nowe narzędzie — HttpClient. Umożliwia wykonywanie żądań HTTP na nowoczesnym poziomie: pracę z metodami GET, POST i innymi, zarządzanie limitami czasu, kontrolę nagłówków i statusów, obsługę przekierowań.

Do pobierania obrazów jest to szczególnie przydatne: możemy upewnić się, że plik faktycznie został pobrany pomyślnie, a nie że dostaliśmy błąd.

Minimalny przykład z HttpClient

URI uri = URI.create("https://example.com/image.jpg");   // URI — bardziej nowoczesna wersja URL

HttpClient client = HttpClient.newHttpClient();          // Tworzymy obiekt HttpClient
HttpRequest request = HttpRequest.newBuilder(uri).build(); // Tworzymy obiekt "żądanie"

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

Teraz krok po kroku:

  1. Tworzymy klienta HttpClient.
  2. Konstruujemy żądanie HttpRequest pod wskazany adres.
  3. Wysyłamy żądanie i otrzymujemy odpowiedź jako tablicę bajtów: HttpResponse.BodyHandlers.ofByteArray().
  4. Zapisujemy te bajty do pliku metodą Files.write"c.jpg".

Rezultat — ten sam obraz, ale teraz mamy więcej informacji o tym, jak dokładnie odpowiedział serwer.

Sprawdzanie statusu odpowiedzi

Obiekt response ma metodę statusCode(). Dzięki niej możemy upewnić się, że serwer zwrócił pomyślną odpowiedź:

if (response.statusCode() == 200)
{
    Files.write(Path.of("ok.jpg"), response.body());
}
else
{
    System.out.println("Błąd: kod " + response.statusCode());
}

Teraz dokładnie wiemy, że zapisaliśmy to, czego oczekiwaliśmy, a nie stronę z błędem.

Pobieranie nagłówków

Załóżmy, że chcemy sprawdzić typ zawartości:

String type = response.headers().firstValue("Content-Type").orElse("nieznany");
System.out.println("Typ zawartości: " + type);

Jeśli serwer zwróci "image/png" lub "image/jpeg", to rzeczywiście jest obraz. Jeśli jednak przyszło "text/html", to sygnał alarmowy.

Limity czasu

Aby program się nie zawiesił, gdy serwer długo odpowiada, można ustawić ograniczenie:

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

Jeśli serwer nie odpowie w ciągu 5 sekund, żądanie zakończy się błędem.

Obsługa przekierowań

Czasem linki nie prowadzą bezpośrednio do pliku, lecz najpierw do strony przekierowującej. Automatyczne podążanie za przekierowaniami można włączyć tak:

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

4. Scenariusze praktyczne

Pobieranie wielu obrazów po kolei

Często trzeba pobrać nie jeden, lecz dziesiątki albo setki obrazów. Na przykład piszesz program, który zapisuje awatary użytkowników lub zdjęcia produktów. Z HttpClient robi się to pętlą:

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());
    }
}

Sprawdzanie rozmiaru pliku

Bywa przydatne wiedzieć, ile bajtów ma obraz. Serwer może to podać w nagłówku "Content-Length":

String length = response.headers().firstValue("Content-Length").orElse("?");
System.out.println("Rozmiar: " + length + " bajtów");

Jeśli nagłówka nie ma, zawsze można po prostu wziąć response.body().length.

Pobranie i wyświetlenie obrazu w programie

Czasem obraz trzeba nie tylko pobrać, ale i od razu wyświetlić. Do tego można użyć biblioteki javax.imageio.ImageIO:

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

W ten sposób możemy sprawdzić obraz od razu w pamięci, nawet nie zapisując go na dysk.

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