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

ダウンロードダイアログの作成

環境/言語:[VB.NET 2002]
分類:[.NET]

サイズが大きいファイルをダウンロードするとき、
http://dobon.net/vb/dotnet/internet/webrequestsavefile.html
のようにしてダウンロードを行い、
'応答データをファイルに書き込む
のWhileのところで何%ダウンロードが完了しているのかを表示しているのですが、
ダウンロード中PCが非常に重くなり、また、普通に
http://dobon.net/vb/dotnet/internet/downloadfile.html
などでダウンロードする場合に比べ非常に時間がかかります。
スペックやOSによって、数秒で終わるPCもあれば数十分かかるPCもあります。

IEでHP上のファイルをダウンロードするときのように、
軽く、速く、すべてのPCで同じように動作させるにはどうしたらよいのでしょうか。
こんにちは中です

ダウンロード処理と画面処理をスレッドで分けて行いましょう。
この処理のままじゃ無限ループしているのでCPU100使ってしまいますね。

------------------------------------------------------
中博俊 MSMVP Visual Studio C# Since 2004/04-2005/03, MCP
http://naka.wankuma.com/
http://naka.wankuma.com/blog/
naka@wankuma.com
Stream.BeginRead メソッドを使うといいんじゃないでしょうか。中さんが指
摘しているスレッドを分けるという方法の一つです。必然的に 1 byte ずつの
読み書きをやめるでしょうから、効率に関しても現在のコードよりずっとよく
なります。
スレッド化は最初考えたのですが、
PCの動作は軽くなるものの余計にダウンロードが遅くなるような気がしたので
やっていませんでした。
自分の知識内で一応スレッド化してみます。

Stream.BeginRead メソッドは、一応いろいろ調べてみたのですが、
どのように使うのかまったく理解できませんでした。すみません。
やはり、スレッド化してみたのですが、
PCの動作が軽くなっただけでダウンロードにはすごく時間がかかります。
(1MB=約1分)
同じファイルをIEで普通にダウンロードしてみましたが、
1MBに2秒もかかりませんでした。

自分がやったスレッド化とは、ただ
http://dobon.net/vb/dotnet/internet/webrequestsavefile.html
をPrivate Sub download()というSubで囲み、Form_Loadイベントで
 Dim th As New System.Threading.Thread(New System.Threading.ThreadStart(AddressOf download))
 th.Start()
としただけです。

初心者の自分ではいろいろ調べてもこれが限界です。
具体的にどのようにしたらよいのか教えていただけないでしょうか。
よろしくお願いします。
> 初心者の自分ではいろいろ調べてもこれが限界です。

説明が書き足りませんでしたね。BeginRead メソッドをおすすめしたのは、時
間のかかる処理を GUI を処理するスレッドから追い出せる、1 byte 単位の読
み書きという非効率な処理を見直すはず、という二つの理由からでした。前者
はアプリケーションの重たい感じを改善しますし、後者はダウンロードの遅さ
を改善するはずです。ご要望にぴったりでしょ。

> 具体的にどのようにしたらよいのか教えていただけないでしょうか。

現在のコードにそっていくなら、

'応答データをファイルに書き込む
Dim buffer(4096) As Byte ' 8192 くらいでもいいかも。
Dim length As Integer
While True
    length = strm.Read(buffer, 0, buffer.Length)
    If length <= 0 Then Exit While
    fs.Write(buffer, 0, length)
End While

という具合に書き換えてみてください。
> 説明が書き足りませんでしたね。BeginRead メソッドをおすすめしたのは、時
> 間のかかる処理を GUI を処理するスレッドから追い出せる、1 byte 単位の読
> み書きという非効率な処理を見直すはず、という二つの理由からでした。前者
> はアプリケーションの重たい感じを改善しますし、後者はダウンロードの遅さ
> を改善するはずです。ご要望にぴったりでしょ。

そのようにできるのが理想です。(要望どおりです)
ただ、BeginReadメソッドの使い方がヘルプなどを読んでもよく分からないので・・・

> '応答データをファイルに書き込む
> Dim buffer(4096) As Byte ' 8192 くらいでもいいかも。
> Dim length As Integer
> While True
> length = strm.Read(buffer, 0, buffer.Length)
> If length <= 0 Then Exit While
> fs.Write(buffer, 0, length)
> End While

なるほど。確かに、自分がスレッド化したプログラムの
'応答データをファイルに書き込む
の部分をこのように書き換えたら、すごく速くなりました。
このようにすれば、いままで1バイトずつ読み書きしていたものを
4096バイトずつにすることができるわけですね。
何バイトずつにするかはいろいろ試して決めます。

できればBeginReadメソッドも使ってみたかったですが、
とてもむずかしくなりそうなのであきらめます。
親切に教えてくださりありがとうございました。
解決済み!
数台のPCで試したのですが、Windows XPでは問題ないものの、
Windows MEで同じプログラムを実行するとPCが非常に重くなり、
マウスカーソルがなめらかに動かなかくなったりします。
スペックが低くてもXPだと重くなりません。

XPよりもMEのほうがダウンロードにも時間がかかります。
 Microsoftからdotnetfx.exe(約23MB)をダウンロードする場合
  XP 40〜50秒(バッファを1024〜8192まで変化させても速度に変化なし)
  ME 約150秒(バッファ8192)〜約450秒(バッファ1024)

速度はやはりバッファを何バイトにするかで変わってくるようなのですが、
このバッファ、増やしすぎたり減らしすぎたりすると、
どのような問題が出てくるのでしょうか。
減らしすぎると遅くなるというのはなんとなく分かるのですが・・・

重くなるPC
 CPU:Celeron 700
 メモリ:320MB
 Windows ME

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