CodeGym /コース /JAVA 25 SELF /インターネットから画像をダウンロードする

インターネットから画像をダウンロードする

JAVA 25 SELF
レベル 12, レッスン 4
使用可能

1. はじめに

ファイルとネットワークの扱いは、プログラミングで非常に重要なテーマです。ほとんどの現代的なアプリは何らかの形でインターネットとやり取りし、データを取得したり、リクエストを送ったり、画像やドキュメントを受け取ったりします。チャットクライアントや音楽プレーヤーのような単純なプログラムでさえ、リソースのダウンロードを扱います。

今日は、Java でそれをどう行うかを、もっとも分かりやすく楽しい題材である画像を例に解説します。なぜ画像なのか?

  • すぐに目に見える: うまく動けば、保存したファイルを開いて画像が見られます。結果が即時で分かりやすい。
  • 汎用的なスキル: 画像は単なる画像ではなく、バイナリデータ、つまり「生のバイト」です。これに慣れれば、ドキュメント、動画、音楽、アーカイブなど何でもダウンロードできます。原理は同じです。
  • 実用的: ネットワークからリソースをダウンロードする力は、壁紙ダウンローダーのようなシンプルなツールから、SNS の API を扱う高度なシステムまで、あらゆる現代アプリの土台になります.

ここでは2つのアプローチを扱います。手早い「郵便サービス」的な URL と、ヘッダー・ステータス・タイムアウトを制御できる「プロの運送会社」的な HttpClient です。

2. 最も簡単な方法: クラス URL

Java には URL クラスがあり、ネットワークアドレスを表します。これで接続を開き、データストリーム(InputStream 型)を取得できます。このストリームはファイルと同様に扱え、バイトを読み出したり、別のストリームにコピーしたり、テキストとして処理したりできます。

要するに、URL を使うのは、ブラウザのリンクからディスク上のファイルまでの最短ルートです。

最初の最小例

例えば、画像へのリンクがあるとします:

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

たった2行です。何をしているのでしょうか?

  1. URL オブジェクトを作成し、画像のアドレス文字列を渡します。
  2. openStream() メソッドを呼び出してネットワーク接続を開き、InputStream を返します。
  3. Files.copy を使って、ストリームの内容をファイル "a.jpg" にコピーします。

結果: インターネット上の画像が作業フォルダに保存されます。

transferTo を使う方法

ストリームからファイルへデータを渡す別の方法もあります:

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

ここでは、in ストリームの全データを transferTo メソッドで、ファイル "b.jpg" を書き出すストリームへ転送するよう明示しています。

結果は同じです: 画像がディスクに保存されます。

重要なポイント

この方法はとても簡単ですが注意点があります。まず、リンクから届いたものが何かをまったく検証していません。画像かもしれませんし、エラー 404 の HTML ページかもしれません。いずれの場合もファイルは保存され、違いが分かるのは画像ビューアで開こうとしたときです。

3. 現代的な方法: HttpClient

Java 11 から標準ライブラリに新しいツール — HttpClient — が加わりました。GET、POST などのメソッドを扱い、タイムアウトを管理し、ヘッダーとステータスを確認し、リダイレクトを処理できます。

画像のダウンロードでは特に有用で、実際にファイルが正常に取得できたか(エラーではないか)を確認できます。

HttpClient の最小例

URI uri = URI.create("https://example.com/image.jpg");   // URI は URL のより現代的な版

HttpClient client = HttpClient.newHttpClient();          // HttpClient オブジェクトを作成
HttpRequest request = HttpRequest.newBuilder(uri).build(); // "リクエスト" オブジェクトを作成

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

手順:

  1. HttpClient クライアントを作成します。
  2. 指定したアドレスに対する HttpRequest を構築します。
  3. リクエストを送信し、応答をバイト配列として受け取ります: HttpResponse.BodyHandlers.ofByteArray()。
  4. Files.write でこれらのバイトをファイル "c.jpg" に書き込みます。

結果は同じく画像が得られますが、サーバーがどのように応答したかについてより多くの情報が得られます。

ステータスコードの確認

response には statusCode() というメソッドがあります。これでサーバーが成功応答を返したか確認できます:

if (response.statusCode() == 200)
{
    Files.write(Path.of("ok.jpg"), response.body());
}
else
{
    System.out.println("エラー: コード " + response.statusCode());
}

これで、エラーページではなく、期待どおりのものを保存したと確信できます。

ヘッダーの取得

たとえば、コンテンツタイプをチェックしたいとします:

String type = response.headers().firstValue("Content-Type").orElse("不明");
System.out.println("コンテンツタイプ: " + type);

サーバーが "image/png" や "image/jpeg" を返したなら、それは本当に画像です。もし "text/html" が来たなら要注意です。

タイムアウト

サーバーの応答が遅くてもプログラムが固まらないよう、制限を設定できます:

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

サーバーが 5 秒以内に応答しない場合、リクエストはエラーで終了します。

リダイレクトの処理

リンクが直接ファイルではなく、まずリダイレクトページに導くことがあります。自動追跡を有効にするには次のとおりです:

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

4. 実践シナリオ

複数の画像を連続でダウンロード

1 枚ではなく数十、数百枚の画像をダウンロードしたいことはよくあります。たとえば、ユーザーのアバターや商品の写真を保存するプログラムを書く場合です。HttpClient を使えばループで簡単に実装できます:

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

ファイルサイズの確認

画像のバイト数を知りたいこともあります。サーバーは "Content-Length" ヘッダーで知らせてくれることがあります:

String length = response.headers().firstValue("Content-Length").orElse("?");
System.out.println("サイズ: " + length + " バイト");

ヘッダーがない場合は、response.body().length を見れば十分です。

ダウンロードしてプログラム内で表示

画像をダウンロードするだけでなく、その場で表示したいこともあります。javax.imageio.ImageIO ライブラリを使えます:

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

このように、ディスクに保存せずにメモリ上で画像をすぐ検証できます。

1
タスク
JAVA 25 SELF, レベル 12, レッスン 4
ロック未解除
URLからのファイルダウンロード
URLからのファイルダウンロード
1
タスク
JAVA 25 SELF, レベル 12, レッスン 4
ロック未解除
transferTo を使ったファイルのダウンロード
transferTo を使ったファイルのダウンロード
1
タスク
JAVA 25 SELF, レベル 12, レッスン 4
ロック未解除
HttpClientを使ったファイルのダウンロード
HttpClientを使ったファイルのダウンロード
1
タスク
JAVA 25 SELF, レベル 12, レッスン 4
ロック未解除
コンテンツタイプとファイルのサイズの取得
コンテンツタイプとファイルのサイズの取得
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION