.NET TIPS

ファイルのダウンロードをレジューム(再開)するには?[C#、VB]

デジタルアドバンテージ 遠藤 孝信
2008/02/21

 現在多くのWebサーバでは、ファイルをダウンロードする際にダウンロードの開始位置を指定できるようになっている。この機能を使えば、何らかの理由で中断してしまったファイルのダウンロードを、中断した位置からレジューム(再開、リジューム)することができる。本稿では、そのコーディング方法について解説する。

HttpWebRequest/HttpWebResponseクラスによるダウンロード

 ここではまず、HttpWebRequest/HttpWebResponseクラス(ともにSystem.Net名前空間)を使用して通常のダウンロード(新規ダウンロード)を行うコードを示す。HttpWebRequest/HttpWebResponseクラスの基本的な使い方については「TIPS:WebRequest/WebResponseクラスでWebページを取得するには?」を参照してほしい。

 このDownloadメソッドは、第1パラメータで指定されたURLのファイルをダウンロードし、第2パラメータで指定されたファイルに書き込む。

using System;
using System.IO;
using System.Net;

public class WebUtil {

  public static void Download(string url, string file) {

    // リクエストの作成
    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);

    // レスポンスの取得
    HttpWebResponse res = (HttpWebResponse)req.GetResponse();

    using (FileStream fs = new FileStream(file, FileMode.Create)) {
      using (Stream st = res.GetResponseStream()) {
        Byte[] buf = new Byte[1024];
        int count = 0;
        do {
          count = st.Read(buf, 0, buf.Length);
          fs.Write(buf, 0, count);
        } while (count != 0);
      }
    }
    res.Close();
  }
}
Imports System
Imports System.IO
Imports System.Net

Public Class WebUtil

  Public Shared Sub Download(ByVal url As String, ByVal file As String)

    ' リクエストの作成
    Dim req As HttpWebRequest _
      = CType(WebRequest.Create(url), HttpWebRequest)

    ' レスポンスの取得
    Dim res As HttpWebResponse _
      = CType(req.GetResponse(), HttpWebResponse)

    Using st As Stream = res.GetResponseStream()
      Using fs As New FileStream(file, FileMode.Create)
        Dim buf(1024) As Byte
        Dim count As Integer = 0
        Do
          count = st.Read(buf, 0, buf.Length)
          fs.Write(buf, 0, count)
        Loop While count <> 0
      End Using
    End Using
    res.Close()
  End Sub
End Class
ファイルのダウンロードを行うDownloadメソッド(上:C#、下:VB)

 ダウンロードのレジュームは、これに若干のコードを追加することで可能だ。

AddRangeメソッドによるダウンロード範囲の指定

 Webサーバに対してダウンロードする範囲を指定するには、リクエスト(=HttpWebRequestオブジェクト)に対してAddRangeメソッドを呼び出して行う。AddRangeメソッドではパラメータとして、ダウンロードを開始する位置を指定できる。

 ダウンロードをレジュームする手順としては、途中までダウンロード済みのファイルのサイズを取得し、その値を開始位置としてダウンロードを行い、それにより取得したデータをそのファイルの末尾に追記していけばよい。

 次のサンプル・プログラムはこれを実装したもので、ダウンロードするファイルのURLと、途中までダウンロード済みのファイルのパス名をコマンドライン引数で指定して実行すれば、ファイルの続き部分のダウンロードが開始される。

// resumedown.cs

using System;
using System.IO;
using System.Net;

public class WebUtil {

  static void Main(string[] args) {

    if (args.Length != 2) {
      return;
    }
    string url = args[0];
    string fileName = args[1];
    long startPos = 0;

    // ファイルがすでに存在する場合、
    // ファイルのサイズを取得する
    if (File.Exists(fileName)) {
      FileInfo info = new FileInfo(fileName);
      startPos = info.Length;
    }
    WebRequest.DefaultWebProxy = null; // プロキシを使用しない
    ResumeDownload(url, fileName, startPos);
  }

  public static bool ResumeDownload(
      string url, string file, long startPos) {

    Console.WriteLine("開始位置:" + startPos);

    // リクエストの作成
    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
    req.AddRange((int)startPos); // ダウンロード開始位置を設定

    // レスポンスの取得
    HttpWebResponse res = (HttpWebResponse)req.GetResponse();

    if (res.StatusCode != HttpStatusCode.PartialContent) {
      // レジュームに対応してない場合
      res.Close();
      return false;
    }

    using (FileStream fs = new FileStream(
        file, FileMode.OpenOrCreate)) {

      fs.Seek(0, SeekOrigin.End); // 末尾に追記

      using (Stream st = res.GetResponseStream()) {
        Byte[] buf = new Byte[1024];
        int count = 0;
        do {
          count = st.Read(buf, 0, buf.Length);
          fs.Write(buf, 0, count);
        } while (count != 0);
      }
      res.Close();
    }
    return true;
  }
}

// コンパイル方法:csc resumedown.cs
// 実行方法:resumedown.exe <URL> <保存先のファイル名>
ダウンロードのレジュームを行うC#のサンプル・プログラム(resumedown.cs)

' resumedown.vb

Imports System
Imports System.IO
Imports System.Net

Public Class WebUtil

  Shared Sub Main(ByVal args As String())

    If args.Length <> 2 Then
      Return
    End If
    Dim url As String = args(0)
    Dim fileName As String = args(1)
    Dim startPos As Long = 0

    ' ファイルがすでに存在する場合、
    ' ファイルのサイズを取得する
    If File.Exists(fileName) Then
      Dim info As New FileInfo(fileName)
      startPos = info.Length
    End If
    WebRequest.DefaultWebProxy = Nothing ' プロキシを使用しない
    ResumeDownload(url, fileName, startPos)
  End Sub

  Public Shared Function ResumeDownload(ByVal url As String, ByVal file As String, ByVal startPos As Long) As Boolean

    Console.WriteLine("開始位置:" & startPos)

    ' リクエストの作成
    Dim req As HttpWebRequest _
      = CType(WebRequest.Create(url), HttpWebRequest)

    ' ダウンロード開始位置を設定
    req.AddRange(CType(startPos, Integer)

    ' レスポンスの取得
    Dim res As HttpWebResponse _
      = CType(req.GetResponse(), HttpWebResponse)

    If res.StatusCode <> HttpStatusCode.PartialContent
      ' レジュームに対応してない場合
      res.Close()
      return False
    End If
    Using fs As New FileStream(file, FileMode.OpenOrCreate)

      fs.Seek(0, SeekOrigin.End) ' 末尾に追記

      Using st As Stream = res.GetResponseStream()
        Dim buf(1024) As Byte
        Dim count As Integer = 0
        Do
          count = st.Read(buf, 0, buf.Length)
          fs.Write(buf, 0, count)
        Loop While count <> 0
      End Using
    End Using
    res.Close()

    Return True
  End Function
End Class

' コンパイル方法:vbc resumedown.vb
' 実行方法:resumedown.exe <URL> <保存先のファイル名>
ダウンロードのレジュームを行うVBのサンプル・プログラム(resumedown.vb)

 ただし、すべてのWebサーバがダウンロードのレジュームに対応しているわけではないので、そのチェックが必要になる。リクエストでダウンロード範囲の指定を行い、Webサーバがレジュームに対応している場合には、Webサーバからのレスポンスのステータス・コードは「206」になる(はずである)。

 この「206」はHttpStatusCode列挙体(System.NET名前空間)のPartialContentとして定義されているので、上記のプログラムでは、この値でレスポンスのステータス・コード(HttpWebResponseオブジェクトのStatusCodeプロパティにより取得可能)をチェックし、Webサーバがレジュームに対応していなければダウンロードを行わないようにしている。

 ちなみに、HttpWebRequestクラスのAddRangeメソッドではダウンロード開始位置だけでなく、開始位置と終了位置を指定することもできる。これを利用すれば、1つのファイルを分割して各部分を同時にダウンロードする、いわゆる「分割ダウンロード」も実装できる。End of Article

カテゴリ:クラス・ライブラリ 処理対象:ネットワーク
使用ライブラリ:HttpWebRequestクラス(System.Net名前空間)
使用ライブラリ:HttpWebResponseクラス(System.Net名前空間)
使用ライブラリ:HttpStatusCodeクラス(System.Net名前空間)
関連TIPS:WebRequest/WebResponseクラスでWebページを取得するには?

この記事と関連性の高い別の.NET TIPS
サーバにより指定されたファイル名でファイルをダウンロードして保存するには?
ファイル・ダウンロード時の最大同時接続数を変更するには?
ファイルをダウンロードさせるには?[JavaScript]
MSDNサブスクリプションで新製品を超高速にダウンロードするには?
HTTPステータス・コードを取得しWebページの存在を確認するには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間