DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

WebRequest、WebResponseクラスを使ってファイルをダウンロードし表示する

WebRequestクラスWebResponseクラスを使って、指定されたURL(URI)のデータを取得する方法を紹介します。

ファイルをダウンロードし保存する」や「ファイルをダウンロードし表示する」で紹介しているWebClientクラスも内部ではWebRequest、WebResponseクラスを使用しています。よって、WebClientクラスだけではできないようなことも、ここで紹介している方法ならできるかもしれません。

早速ですが、具体例を示します。次の例では、「http://www.microsoft.com」からデータをダウンロードして、HTMLソースを表示しています。

VB.NET
コードを隠すコードを選択
'HttpWebRequestを作成
Dim webreq As System.Net.HttpWebRequest = _
    DirectCast(System.Net.WebRequest.Create("http://www.microsoft.com"),  _
        System.Net.HttpWebRequest)
'または、
'Dim webreq As System.Net.WebRequest = _
'    System.Net.WebRequest.Create("http://www.microsoft.com")

'サーバーからの応答を受信するためのHttpWebResponseを取得
Dim webres As System.Net.HttpWebResponse = _
    DirectCast(webreq.GetResponse(), System.Net.HttpWebResponse)
'または、
'Dim webres As System.Net.WebResponse = webreq.GetResponse()

'応答データを受信するためのStreamを取得
Dim st As System.IO.Stream = webres.GetResponseStream()
'文字コードを指定して、StreamReaderを作成
Dim sr As New System.IO.StreamReader(st, System.Text.Encoding.UTF8)
'データをすべて受信
Dim htmlSource As String = sr.ReadToEnd()
'閉じる
sr.Close()
st.Close()
webres.Close()
'「st.Close()」や「webres.Close()」だけでもよい

'取得したソースを表示する
Console.WriteLine(htmlSource)
C#
コードを隠すコードを選択
//HttpWebRequestを作成
System.Net.HttpWebRequest webreq =
    (System.Net.HttpWebRequest)
        System.Net.WebRequest.Create("http://www.microsoft.com");
//または、
//System.Net.WebRequest webreq =
//    System.Net.WebRequest.Create("http://www.microsoft.com");

//サーバーからの応答を受信するためのHttpWebResponseを取得
System.Net.HttpWebResponse webres =
    (System.Net.HttpWebResponse)webreq.GetResponse();
//または、
//System.Net.WebResponse webres = webreq.GetResponse();

//応答データを受信するためのStreamを取得
System.IO.Stream st = webres.GetResponseStream();
//文字コードを指定して、StreamReaderを作成
System.IO.StreamReader sr =
    new System.IO.StreamReader(st, System.Text.Encoding.UTF8);
//データをすべて受信
string htmlSource = sr.ReadToEnd();
//閉じる
sr.Close();
st.Close();
webres.Close();
//「st.Close()」や「webres.Close()」だけでもよい

//取得したソースを表示する
Console.WriteLine(htmlSource);

この例では取得するHTMLソースの文字コードがUTF-8のため「Encoding.UTF8」を使用していますが、別の文字コードの場合は別のEncodingオブジェクトを使用する必要があります。詳しくは、「目的の文字コードに合ったEncodingオブジェクトを取得する」をご覧ください。

補足:StreamReaderが使用するエンコーディングはデフォルトでUTF-8ですので、上記の例では「Encoding.UTF8」を省略できます。

WebRequestインスタンスは、WebRequest.Createメソッドで作成します。この時、指定されたURIによって、適切なWebRequestクラスの派生クラスが返されます。例えば、上記のようにURIのスキームがhttp://またはhttps://の場合は、HttpWebRequestクラスのインスタンスを返します。また、file://の場合は、FileWebRequestクラスを返します。さらに、.NET Framework 2.0以降では、ftp://の場合、FtpWebRequestクラスを返します。

補足:上記の例ではURIのスキームがhttp://のため、WebRequest.Createメソッドが返すインスタンスをHttpWebRequest型にキャストしていますが、file://やftp://の場合は、FileWebRequestやFtpWebRequestにキャストする必要があります(またはコメントのように、WebRequest型として取得します)。「HttpWebResponse」も同様です。

非同期でダウンロードする

上記の方法は同期処理のため、受信が完了するまでの間、フリーズしたようになります。これを解決するには、スレッド化するか、非同期処理を行います。ここでは非同期処理の方法について、具体的な例を紹介します。

非同期処理では、まずWebRequest.BeginGetResponseメソッドにより、サーバーからの応答を要求し、待機します。さらに、データを非同期で受信するために、Stream.BeginReadメソッドで読み込みを開始します。

次に示すコンソールアプリケーションのサンプルでは、非同期で「http://www.microsoft.com」からデータを受信し、表示しています。

なおこのような非同期処理では、マルチスレッドプログラミングの知識がある程度必要になります。マルチスレッドプログラミングについては、「.NETのマルチスレッドプログラミング」を参考にしてください。

VB.NET
コードを隠すコードを選択
Class MainClass
    '受信した全データを入れておくMemoryStream
    Private Shared requestData As System.IO.MemoryStream
    '受信したデータが一時的に入るバイト型配列
    Private Shared bufferData As Byte()

    'エントリポイント
    Public Shared Sub Main()
        'HttpWebRequestを作成
        Dim webreq As System.Net.HttpWebRequest = DirectCast( _
            System.Net.WebRequest.Create("http://www.microsoft.com"),  _
            System.Net.HttpWebRequest)

        '非同期要求を開始
        '状態オブジェクトとしてHttpWebRequestを渡す
        Dim r As IAsyncResult = DirectCast( _
            webreq.BeginGetResponse( _
                New AsyncCallback(AddressOf ResponseCallback), webreq),  _
            IAsyncResult)

        'アプリケーションが終わらないように待機する
        Console.ReadLine()
    End Sub

    '非同期要求が終了した時に呼び出されるコールバックメソッド
    Private Shared Sub ResponseCallback(ar As IAsyncResult)
        '状態オブジェクトとして渡されたHttpWebRequestを取得
        Dim webreq As System.Net.HttpWebRequest = _
            DirectCast(ar.AsyncState, System.Net.HttpWebRequest)

        '非同期要求を終了
        Dim webres As System.Net.HttpWebResponse = _
            DirectCast(webreq.EndGetResponse(ar), System.Net.HttpWebResponse)

        'データを読み込むためのストリームを取得
        Dim st As System.IO.Stream = webres.GetResponseStream()

        'データを読み込むための準備をする
        requestData = New System.IO.MemoryStream()
        bufferData = New Byte(1023) {}

        '非同期でデータの読み込みを開始
        '状態オブジェクトとしてStreamを渡す
        Dim r As IAsyncResult = DirectCast( _
            st.BeginRead(bufferData, 0, bufferData.Length, _
                New AsyncCallback(AddressOf ReadCallback), st),  _
            IAsyncResult)
    End Sub

    '非同期読み込み完了時に呼び出されるコールバックメソッド
    Private Shared Sub ReadCallback(ar As IAsyncResult)
        '状態オブジェクトとして渡されたStreamを取得
        Dim st As System.IO.Stream = _
            DirectCast(ar.AsyncState, System.IO.Stream)

        'データを読み込む
        Dim readSize As Integer = st.EndRead(ar)

        'データが読み込めたか調べる
        If readSize > 0 Then
            'データが読み込めた時
            '読み込んだデータをMemoryStreamに保存する
            requestData.Write(bufferData, 0, readSize)

            Console.WriteLine("{0}バイト 読み込み完了", requestData.Length)

            '再び非同期でデータを読み込む
            Dim r As IAsyncResult = DirectCast( _
                st.BeginRead(bufferData, 0, bufferData.Length, _
                    New AsyncCallback(AddressOf ReadCallback), st),  _
                IAsyncResult)
        Else
            'データの読み込みが終了した時
            'ダウンロードしたデータをバイト型配列に変換
            Dim sourceData As Byte() = requestData.ToArray()
            'データを文字列に変換
            Dim sourceHtml As String = _
                System.Text.Encoding.UTF8.GetString(sourceData)
            '結果を表示する
            Console.Write(sourceHtml)

            '閉じる
            st.Close()
            requestData.Close()
        End If
    End Sub
End Class
C#
コードを隠すコードを選択
using System;

class MainClass
{
    //受信した全データを入れておくMemoryStream
    private static System.IO.MemoryStream requestData;
    //受信したデータが一時的に入るバイト型配列
    private static byte[] bufferData;

    //エントリポイント
    public static void Main()
    {
        //HttpWebRequestを作成
        System.Net.HttpWebRequest webreq = (System.Net.HttpWebRequest)
            System.Net.WebRequest.Create("http://www.microsoft.com");

        //非同期要求を開始
        //状態オブジェクトとしてHttpWebRequestを渡す
        IAsyncResult r = (IAsyncResult)webreq.BeginGetResponse(
            new AsyncCallback(ResponseCallback), webreq);

        //アプリケーションが終わらないように待機する
        Console.ReadLine();
    }

    //非同期要求が終了した時に呼び出されるコールバックメソッド
    private static void ResponseCallback(IAsyncResult ar)
    {
        //状態オブジェクトとして渡されたHttpWebRequestを取得
        System.Net.HttpWebRequest webreq =
            (System.Net.HttpWebRequest)ar.AsyncState;

        //非同期要求を終了
        System.Net.HttpWebResponse webres =
            (System.Net.HttpWebResponse)webreq.EndGetResponse(ar);

        //データを読み込むためのストリームを取得
        System.IO.Stream st = webres.GetResponseStream();

        //データを読み込むための準備をする
        requestData = new System.IO.MemoryStream();
        bufferData = new byte[1024];

        //非同期でデータの読み込みを開始
        //状態オブジェクトとしてStreamを渡す
        IAsyncResult r = (IAsyncResult)st.BeginRead(
            bufferData, 0, bufferData.Length,
            new AsyncCallback(ReadCallback), st);
    }

    //非同期読み込み完了時に呼び出されるコールバックメソッド
    private static void ReadCallback(IAsyncResult ar)
    {
        //状態オブジェクトとして渡されたStreamを取得
        System.IO.Stream st = (System.IO.Stream)ar.AsyncState;

        //データを読み込む
        int readSize = st.EndRead(ar);

        //データが読み込めたか調べる
        if (readSize > 0)
        {
            //データが読み込めた時
            //読み込んだデータをMemoryStreamに保存する
            requestData.Write(bufferData, 0, readSize);

            Console.WriteLine("{0}バイト 読み込み完了", requestData.Length);

            //再び非同期でデータを読み込む
            IAsyncResult r = (IAsyncResult)st.BeginRead(
                bufferData, 0, bufferData.Length,
                new AsyncCallback(ReadCallback), st);
        }
        else
        {
            //データの読み込みが終了した時
            //ダウンロードしたデータをバイト型配列に変換
            byte[] sourceData = requestData.ToArray();
            //データを文字列に変換
            string sourceHtml =
                System.Text.Encoding.UTF8.GetString(sourceData);
            //結果を表示する
            Console.Write(sourceHtml);

            //閉じる
            st.Close();
            requestData.Close();
        }
    }
}
補足:BeginGetResponseメソッドではWebRequest.Timeoutプロパティは無視されますので、タイムアウト処理は自分で行う必要があります。MSDNの「HttpWebRequest.BeginGetResponse メソッド」にあるサンプルではタイムアウト処理がされていますので、参考になります。
  • 履歴:
  • 2007/1/20 .NET Framework 2.0に関する記述を追加。
  • 2014/8/21 サンプルのダウンロード先のURLを変更など。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • このサイトで紹介されているコードの多くは、例外処理が省略されています。例外処理については、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。