明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

用VB編寫異步多線程下載程序

[摘要]為了高效率地下載某站點(diǎn)的網(wǎng)頁,我們可利用VB的Internet Transfer 控件編寫自己的下載程序, Internet Transfer 控件支持超文本傳輸協(xié)議(HTTP) 和文件傳輸協(xié)議 (FTP),使用 Internet Transfer 控件可以通過 OpenURL 或 Execute...
為了高效率地下載某站點(diǎn)的網(wǎng)頁,我們可利用VB的Internet Transfer 控件編寫自己的下載程序, Internet Transfer 控件支持超文本傳輸協(xié)議(HTTP) 和文件傳輸協(xié)議 (FTP),使用 Internet Transfer 控件可以通過 OpenURL 或 Execute 方法連接到任何使用這兩個(gè)協(xié)議的站點(diǎn)并檢索文件。本程序使用多個(gè)Internet Transfer 控件,使其同時(shí)下載某站點(diǎn)。并可判斷文件是否已下載過或下載過的文件是否比服務(wù)器上當(dāng)前的文件陳舊,以決定是否重新下載。所有下載的文件中的鏈接都做了調(diào)整,以便于本地查閱。

  OpenURL 方法以同步方式傳輸數(shù)據(jù)。同步指的是傳輸操作未完成之前,不能執(zhí)行其它過程。這樣數(shù)據(jù)傳輸就必須在執(zhí)行其它代碼之前完成。

  而 Execute 方法以異步方式傳輸數(shù)據(jù)。在調(diào)用 Execute 方法時(shí),傳輸操作與其它過程無關(guān)。這樣,在調(diào)用 Execute 方法后,在后臺(tái)接收數(shù)據(jù)的同時(shí)可執(zhí)行其它代碼。

  用 OpenURL 方法能夠直接得到可保存到磁盤的數(shù)據(jù)流,或者直接在 TextBox 控件中閱覽(如果數(shù)據(jù)是文本格式的)。而用 Execute 方法獲取數(shù)據(jù),則必須用 StateChanged 事件監(jiān)視該控件的連接狀態(tài)。當(dāng)達(dá)到適當(dāng)?shù)臓顟B(tài)時(shí),調(diào)用 GetChunk 方法從控件的緩沖區(qū)獲取數(shù)據(jù)。

  首先,建立啟始的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方法。


 
  事件監(jiān)控子程序(每個(gè)Internet Transfer 控件設(shè)置相對(duì)應(yīng)的事件監(jiān)控子程序):

  用StateChanged 事件監(jiān)視該控件的連接狀態(tài), 當(dāng)該請(qǐng)求已經(jīng)完成,并且所有數(shù)據(jù)均已接收到時(shí),調(diào)用 GetChunk 方法從控件的緩沖區(qū)獲取數(shù)據(jù)。

Private Sub Inet1_StateChanged(ByVal State As Integer)
'State = 12 時(shí),使用 GetChunk 方法檢索服務(wù)器的響應(yīng)。
Select Case State
'...沒有列舉其它情況。
 
Case icResponseCompleted '12
'獲取links(g)中的協(xié)議、主機(jī)和路徑名。
addsuf = Left(links(g), InStrRev(links(g), "/"))
'獲取links(g)中的文件名。
fname = Right(links(g), Len(links(g)) - InStrRev(links(g), "/"))
'判斷是否是超文本文件,是超文本文件則分析其中的鏈接,若不是則存為二進(jìn)制文件。
If InStr(1, fname, "htm", vbTextCompare) = True Then
'初始化用于保存文件的FileSystemObject對(duì)象。
Set fs = CreateObject("Scripting.FileSystemObject")
Dim vtData As Variant '數(shù)據(jù)變量。
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
 
'獲取文檔中的鏈接并置于數(shù)組中。
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)
'如果有引號(hào),去掉引號(hào)
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 '調(diào)用線程調(diào)度子程序
End Select
 
End Sub
 
Private Sub Inet2_StateChanged(ByVal State As Integer)
...
end sub
 
...

 
  線程調(diào)度子程序,g和是k公用變量,k為最后一個(gè)鏈接的數(shù)組索引加一,g初值為零,每次加一,直到處理完最后一個(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 ("下載結(jié)束。")
End If