Java

URLからファイルをダウンロードする

本稿では、URLからファイルをダウンロードする方法について解説します。

こんな人におすすめ
  • ファイルのダウンロードを自動化したい
  • 初期処理等のため、プログラム上でファイルをダウンロードする必要がある

Javaの標準ライブラリであるIOパッケージやNIOパッケージによる実装方法、Apache HttpComponentsなどの外部ライブラリを用いた実装方法についていくつかサンプルを掲載しています。

ダウンロードしている間に処理をブロックしたくない場合は、非同期でダウンロードできる方法を参照してください。

URLからファイルを非同期ダウンロードする本稿では、URLからファイルを非同期でダウンロードする方法について解説します。 Javaの標準ライブラリによる実装方法やA...

Java IO を使う方法

ファイルをダウンロードするためには java.io パッケージの機能のみで十分可能ですが、ブラウザでファイルをダウンロードするように単純なメソッドはありません。

以下は、接続したURLからInputStreamを取得し、FileOutputStreamに書き込むサンプルになります。

Java

public void download(URL url) throws IOException {

    String path = url.getPath();
    String name = path.substring(path.lastIndexOf("/") + 1);
    int size = 0;

    try (DataInputStream in = new DataInputStream(url.openStream());
         DataOutputStream out = new DataOutputStream(new FileOutputStream(name))) {

        byte[] buf = new byte[8192];
        int len = 0;

        //入力ストリームからバイト配列に読み込む。ストリームが終端に達した場合は -1 が返る
        while ((len = in.read(buf)) != -1) {
            //バイト配列を出力ストリームに書き込む
            out.write(buf, 0, len);
            size += len;
        }

        //バッファリングされていたすべての出力バイトを強制的に書き込む
        out.flush();
    }

    System.out.println(name + " - " + size + " bytes");
}

上のサンプルではurl.openStream()で直接ストリームを開いていますが、ファイルが存在しない場合を考慮したい場合は次のようにレスポンスコードを判定した上でconn.getInputStream()でストリームを取得する方法もあります。

Java

HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.connect();

if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
    //handle error.
}

InputStream in = conn.getInputStream();

また、上のサンプルでは単純はread/writeのため省いていますが、パフォーマンス向上のためにはBufferedInputStream/BufferedOutputStreamを使うことをおすすめします。

Java

try (DataInputStream in =
             new DataInputStream(
                     new BufferedInputStream(url.openStream()));
     DataOutputStream out =
             new DataOutputStream(
                     new BufferedOutputStream(
                             new FileOutputStream(name)))) {

    //処理
}

BufferedInputStreamとDataInputStreamは排他的ではなく、両方を使用できます。

BufferedInputStreamは読み込みをバッファリングしてアクセスする速度を最適化し、DataInputStreamはプラットフォーム依存しないようにデータを読み込み、それ自体は入力をバッファリングしません。

テキストであればBufferedInputStreamを使用し、バイナリレベルで制御が必要な場合はDataInputStreamも使用するなど、入力ソースに応じて書き換えてください。

Java NIO を使う方法

java.nio パッケージを使用すると、チャネル間でデータを転送することができるため、いちいちメモリに読み込む必要がなくなります。

java.io パッケージを使用した方法に比べて、一般的には高速に処理することができます。

Java

public void download(URL url) throws IOException {

    String path = url.getPath();
    String name = path.substring(path.lastIndexOf("/") + 1);
    long size = 0L;

    try (ReadableByteChannel bc = Channels.newChannel(url.openStream());
         FileChannel fc = new FileOutputStream(name).getChannel()) {

        //ファイルチャネルへデータを転送する
        size = fc.transferFrom(bc, 0, Long.MAX_VALUE);
    }

    System.out.println(name + " - " + size + " bytes");
}

また、JavaSE7以降はFilesヘルパが追加されており、よりシンプルに実装することもできます。

Java

public void download(URL url) throws IOException {

    String path = url.getPath();
    String name = path.substring(path.lastIndexOf("/") + 1);
    long size = 0;

    //StandardCopyOption.REPLACE_EXISTING を指定した場合は、
    //すでにファイルが存在していたら上書きされる
    size = Files.copy(url.openStream(), Paths.get(name), REPLACE_EXISTING);

    System.out.println(name + " - " + size + " bytes");
}

Apache HttpComponents を使う方法

org.apache.http パッケージを使用してファイルをダウンロードします。

GETやPOSTなどHTTPメソッドを簡単に使い分けできます。ただしこのライブラリじゃないとできないというものではなく、ライブラリ自体も標準機能の薄いラッパーなので、このケースでは積極的に使用しなくても困らないように思います。

セットアップ

Mavenを使用する場合は、pom.xmlに以下の依存性を追加してください。

pom.xml

<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.10</version>
</dependency>

特にプロジェクト管理ツールを使わない場合はより公式よりzipをダウンロードして、プロジェクトにjarを追加してください。

ソースコード

Java

public void download(URI uri) throws IOException {

    String path = uri.getPath();
    String name = path.substring(path.lastIndexOf("/") + 1);
    long size = 0;

    try (CloseableHttpClient client = HttpClients.createDefault();
         CloseableHttpResponse response = client.execute(new HttpGet(uri))) {

        //レスポンスのEntityからInputStreamを取得する
        InputStream is = response.getEntity().getContent();

        //ファイル保存は他のパターンと同じ
        size = Files.copy(is, Paths.get(name));
    }

    System.out.println(name + " - " + size + " bytes");
}

Entityからデータをバイト配列に読み込むユーティリティも用意されています。入力ソースのサイズが大きい場合は注意が必要です。

byte[] data = EntityUtils.toByteArray(response.getEntity());

Google Http Client を使う方法

Apache HttpComponents と同じく、基本的には java.io のラッパーです。

セットアップ

Mavenを使用する場合は、pom.xmlに以下の依存性を追加してください。

pom.xml

<!-- https://mvnrepository.com/artifact/com.google.http-client/google-http-client -->
<dependency>
    <groupId>com.google.http-client</groupId>
    <artifactId>google-http-client</artifactId>
    <version>1.32.1</version>
</dependency>

特にプロジェクト管理ツールを使わない場合はMavenのCentralリポジトリよりjarをダウンロードしてください。

google-http-client-1.32.1.jar

ソースコード

Java

//ファクトリーを生成する
//(NetHttpTransport -> HTTP接続は標準ライブラリを使用する)
private static HttpRequestFactory factory =
        new NetHttpTransport().createRequestFactory();

public void download(URI uri) throws IOException {

    String path = uri.getPath();
    String name = path.substring(path.lastIndexOf("/") + 1);

    //リクエストの生成
    HttpRequest request = factory.buildGetRequest(new GenericUrl(uri));
    //リクエストの送信
    HttpResponse response = request.execute();

    try(FileOutputStream out = new FileOutputStream(name)) {
        //ファイルとしてダウンロードする
        response.download(out);
    }
}

補足

サンプルでは省略していますが、レスポンスをファイルに保存する前に、レスポンスコードを確認してください。

レスポンスとして404(File Not Found)が帰ってきた場合は、取得するコンテンツは空か、あるいはFile Not Foundである旨のhtmlになると思いますが、接続先の実装に依存します。

ABOUT ME
sasakiyu
ひ弱で優しい少年だったが、デーモンと合体。 強大な力を得つつも人間の心を失わないデベルマンとなる。