用VB编写异步多线程下载程序

[入库:2005年8月18日] [更新:2007年3月24日]

本文简介:选择自 tripofdream 的 blog


作者:大庆油田有限公司勘探开发研究院网络室 满孝
为了高效率地下载某站点的网页,我们可利用vb的internet transfer 控件编写自己的下载程序, internet transfer 控件支持超文本传输协议 (http) 和文件传输协议 (ftp),使用 internet transfer 控件可以通过 openurl 或 execute 方法连接到任何使用这两个协议的站点并检索文件。本程序使用多个internet transfer 控件,使其同时下载某站点。并可判断文件是否已下载过或下载过的文件是否比服务器上当前的文件陈旧,以决定是否重新下载。所有下载的文件中的链接都做了调整,以便于本地查阅。 
openurl 方法以同步方式传输数据。同步指的是传输操作未完成之前,不能执行其它过程。这样数据传输就必须在执行其它代码之前完成。 
而 execute 方法以异步方式传输数据。在调用 execute 方法时,传输操作与其它过程无关。这样,在调用 execute 方法后,在后台接收数据的同时可执行其它代码。 
用 openurl 方法能够直接得到可保存到磁盘的数据流,或者直接在 textbox 控件中阅览(如果数据是文本格式的)。而用 execute 方法获取数据,则必须用 statechanged 事件监视该控件的连接状态。当达到适当的状态时,调用 getchunk 方法从控件的缓冲区获取数据。 
  
首先,建立启始的http检索连接, 
public g as variant 
public k as variant 
public spath as string 
dim links() as string 
g = 0 
spath = 本地保存下载文件的路径 
links(0)=启始url 
inet1.execute links(0), "get" '使用get方法。 
  
事件监控子程序(每个internet transfer 控件设置相对应的事件监控子程序): 
用statechanged 事件监视该控件的连接状态, 当该请求已经完成,并且所有数据均已接收到时,调用 getchunk 方法从控件的缓冲区获取数据。 
private sub inet1_statechanged(byval state as integer) 
'state = 12 时,使用 getchunk 方法检索服务器的响应。 
select case state 
'...没有列举其它情况。 
  
case icresponsecompleted '12 
'获取links(g)中的协议、主机和路径名。 
addsuf = left(links(g), instrrev(links(g), "/")) 
'获取links(g)中的文件名。 
fname = right(links(g), len(links(g)) - instrrev(links(g), "/")) 
'判断是否是超文本文件,是超文本文件则分析其中的链接,若不是则存为二进制文件。 
if instr(1, fname, "htm", vbtextcompare) = true then 
'初始化用于保存文件的filesystemobject对象。 
set fs = createobject("scripting.filesystemobject") 
dim vtdata as variant '数据变量。 
dim strdata as string: strdata = "" 
dim bdone as boolean: bdone = false 
  
'取得第一块。 
vtdata = inet1.getchunk(1024, icstring) 
doevents 
do while not bdone 
strdata = strdata & vtdata 
doevents 
'取得下一块。 
vtdata = inet1.getchunk(1024, icstring) 
if len(vtdata) = 0 then 
bdone = true 
end if 
loop 
  
'获取文档中的链接并置于数组中。 
dim i as variant 
dim po1 as variant 
dim po2 as variant 
dim oril as string 
dim newl as string 
dim lmtime, ctime 
po1 = instr(1, strdata, "href=", vbtextcompare) + 5 
po2 = 1 
dim newstr as string: newstr = "" 
dim whostr as string: whostr = "" 
i = 0 
do while po1 > 0 
newstr = mid(strdata, po2, po1) 
whostr = whostr + newstr 
po2 = instr(po1, strdata, ">", vbtextcompare) 
'将原链接改为新链接 
oril = mid(strdata, po1 + 1, po2 - po1 - 1) 
'如果有引号,去掉引号 
ln = replace(oril, """", "", vbtextcompare) 
newl = right(ln, len(ln) - instrrev(ln, "/")) 
whostr = whostr & newl 
if ln <> "" then 
'判定文件是否下载过。 
if fileexists(spath & newl) = false then 
links(i) = addsuf & ln 
i = i + 1 
else 
lmtime = inet1.getheader("last-modified") 
set f = fs.getfile(spath & newl) 
ctime = f.datecreated 
'判断文件是否更新 
if datediff("s", lmtime, ctime) < 0 then 
i = i + 1 
end if 
end if 
end if 
po1 = instr(po2 + 1, strdata, "href=", vbtextcompare) + 5 
loop 
newstr = mid(strdata, po2) 
whostr = whostr + newstr 
  
set a = fs.createtextfile(spath & fname, true) 
a.write whostr 
a.close 
k = i 
else 
dim vtdata as variant 
dim b() as byte 
dim bdone as boolean: bdone = false 
vtdata = inet2.getchunk(1024, icbytearray) 
do while not bdone 
b() = b() & vtdata 
vtdata = inet2.getchunk(1024, icbytearray) 
if len(vtdata) = 0 then 
bdone = true 
end if 
loop 
open spath & fname for binary access write as #1 
put #1, , b() 
close #1 
end if 
call devjob '调用线程调度子程序 
end select 
  
end sub 
  
private sub inet2_statechanged(byval state as integer) 
... 
end sub 
  
... 
  
线程调度子程序,g和是k公用变量,k为最后一个链接的数组索引加一,g初值为零,每次加一,直到处理完最后一个链接。 
private sub devjob() 
  
if not g + 1 < k then goto reportline 
if inet1.stillexecuting = false then 
g = g + 1 
inet1.execute links(g), "get" 
end if 
if not g + 1 < k then goto reportline 
if inet2.stillexecuting = false then 
g = g + 1 
inet2.execute links(g), "get" 
end if 
  
... 
  
reportline: 
if inet1.stillexecuting = false and inet2.stillexecuting = false and ... then 
msgbox ("下载结束。") 
end if 
end sub

本文关键:下载
  相关方案
Google
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top