DOBON.NET DOBON.NETプログラミング掲示板過去ログ

ファイルの連続ダウンロード

環境/言語:[VS2005 C#]
分類:[.NET]

お世話になります。
http://dobon.net/vb/dotnet/internet/downloadfile.html#section3の
「.NET Framework 2.0以降で、非同期的にファイルをダウンロードし保存する」を
参考にファイルのダウンロード処理を作成しました。

ダウンロードするファイルが1つの場合は問題ないのですが
複数の場合はどのように処理を行ったら良いのでしょうか?
複数ファイル分、DownloadFileAsyncをループするようにし
フラグを設けて、downloadClient.DownloadFileAsync(u, fileName);を
開始したら、downloadClient_DownloadFileCompletedが呼ばれるまで
無限ループで待つというような処理を作ったのですが
画面が固まったようになってしまい、うまくいきませんでした。

さらに、ヘルプを調べてIsBusyという値があったので
フラグの変わりにwhile (downloadClient.IsBusy)として待ってみたのですが
コレも上手くいきませんでした。

やりたい事は、Windowsアップデータの際のダウンロード画面のように
複数のファイルを同時にではなく連続でダウンロードしたいと思っています。

よろしくお願いします。


開発環境
VS2005 C#
WindowsXP
■No23752に返信(としさんの記事)
> 開始したら、downloadClient_DownloadFileCompletedが呼ばれるまで
> 無限ループで待つというような処理を作ったのですが

イベントの発生を、ループ待機している理由は何でしょうか?

たとえば ComboBox を貼ったフォームがあったとして、そこで選択された項目を
Label に転記するコードを書くとしたら、ComboBox1_SelectedIndexChanged 内に
Label1.Text = 〜 などと記述するかと思いますが、そのイベントの発生を
無限ループで待機したりはしないですよね。
回答ありがとうございます。

>イベントの発生を、ループ待機している理由は何でしょうか?
1つ目のダウンロードが完了してから、2つ目のダウンロードを始めたい為に
ダウンロード中のファイルのダウンロードが完了するのを待つために
ループで待機しています。

>Label に転記するコードを書くとしたら、ComboBox1_SelectedIndexChanged 内に
>Label1.Text = 〜 などと記述するかと思いますが、そのイベントの発生を
>無限ループで待機したりはしないですよね。
しないですね、という事は・・・・
待たなくても内部の方で待ってくれるから連続でやっても大丈夫なのかな?
と思って待たないで連続でやってみたら、「サポートされていません」のような
エラーメッセージが表示されてしまいました。

ループしている以上、何かが完了するまで「待つ」という処理が入ると思うのですが
この場合は、ファイルのダウンロードが完了するまで待ちたいのですが
その方法がわかりません。
ヒントでも良いので、よろしくお願いします。
ダウンロード終了まで待機するのであれば非同期の意味がありませんので、もしそうしたいのであれば、通常の方法でダウンロードした方が良いのではないでしょうか?

想像ですが、もしかしたらダウンロードするファイルの数だけWebClientオブジェクトを作成していないのではないでしょうか?現在ダウンロードを行っているWebClientオブジェクトを使って別のファイルをダウンロードすることは当然できません。よって新たにWebClientオブジェクトを作成する必要があります。
回答ありがとうございます。

>通常の方法でダウンロードした方が良いのではないでしょうか?
大きなファイルをダウンロードしている途中でキャンセルが出来た方が
使う側から見て便利かな、と思いました。

>ダウンロードするファイルの数だけWebClientオブジェクトを作成していないのではないでしょうか?
ご指摘の通りでした。WebClientオブジェクトを作成するようにしたらエラーにならずに
ファイルをダウンロードすることが出来ました。
ただ、この方法だと連続というより同時にダウンロードしている感じになるので
ちょっとイメージと違いました。

考えてみたのですが、ダウンロード関数を作って
ボタン押下時にその関数を呼んで、さらにdownloadClient_DownloadFileCompletedが
呼ばれたら、またその関数を呼んで・・・という感じの処理を
作ってみたら、ソレっぽく出来ました。
ただし、この段階で
>ダウンロード終了まで待機するのであれば非同期の意味がありませんので
の言わんとしている事がわかったような気がします。

全ファイルのダウンロードがどのようにして完了したのか(正常かエラーか中断か)
また、全て正常で終了した場合に次の処理を呼ぶための方法などを考えていくと、
小細工ばかりになってしまって少々不安を覚えました。
なのでコレはコレとして、次は通常の方法でやってみたいと思います。

また、作成したソースも載せておきます。
後学のためにも、「ここはこの方が良い」とか「コレだとココがダメ」とか
ご意見ありましたら、よろしくお願いします。

System.Net.WebClient downloadClient = null;
int m_iMax;
int m_iCount;
ArrayList m_list;

private void button1_Click(object sender, EventArgs e)
{

    m_list = new ArrayList();
    m_list.Add("ダウンロードファイル1");
    m_list.Add("ダウンロードファイル2");
    m_list.Add("ダウンロードファイル3");

    m_iCount = 0;
    m_iMax = m_list.Count;

    DownLoadFile();
}

private int DownLoadFile()
{
    if(m_list == null){
        return -1;
    }
    if(m_list.Count == 0){
        return -1;
    }
    button1.Enabled = false;
    button2.Enabled = true;

    String strMsg;
    m_iCount++;
    strMsg = String.Format("{0}/{1}", m_iCount, m_iMax);
    label2.Text = strMsg;

    string strUrl = m_list[0].ToString();
    m_list.RemoveAt(0);
    //ダウンロードしたファイルの保存先
    string fileName = "C:\\temp\\" + System.IO.Path.GetFileName(strUrl);
    //ダウンロード基のURL
    Uri u = new Uri(strUrl);

    //WebClientの作成
    if (downloadClient == null)
    {
        downloadClient = new System.Net.WebClient();
        //イベントハンドラの作成
        downloadClient.DownloadProgressChanged +=
            new System.Net.DownloadProgressChangedEventHandler(
                downloadClient_DownloadProgressChanged);
        downloadClient.DownloadFileCompleted +=
            new System.ComponentModel.AsyncCompletedEventHandler(
                downloadClient_DownloadFileCompleted);
    }
    //非同期ダウンロードを開始する
    downloadClient.DownloadFileAsync(u, fileName);

    return 0;
}

private void button2_Click(object sender, EventArgs e)
{
    //非同期ダウンロードをキャンセルする
    if (downloadClient != null)
        downloadClient.CancelAsync();
}

private void downloadClient_DownloadProgressChanged(object sender,
    System.Net.DownloadProgressChangedEventArgs e)
{
    String strMsg;
    strMsg = String.Format("{0}% ({1}byte 中 {2}byte) ダウンロードが終了しました。",
        e.ProgressPercentage, e.TotalBytesToReceive, e.BytesReceived);
    label1.Text = strMsg;
}

private void downloadClient_DownloadFileCompleted(object sender,
    System.ComponentModel.AsyncCompletedEventArgs e)
{
    downloadClient.Dispose();
    downloadClient = null;
    button1.Enabled = true;
    button2.Enabled = false;

    String strMsg;
    if (e.Error != null){
        strMsg = String.Format("エラー:{0}", e.Error.Message);
    }else if (e.Cancelled){
        strMsg = String.Format("キャンセルされました。");
    }else{
        strMsg = String.Format("ダウンロードが完了しました。");
        DownLoadFile();
    }
    label1.Text = strMsg;
}
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板