|
-
May 25th, 2010, 12:59 PM
#1
Thread Starter
Fanatic Member
Download structure fails
Hello all.
I am totally into structures at this point, mostly because of their simplicity in use. 
I am now working on a "download structure", which allows you to download and keep track on a file.
This is the code:
Code:
Public Structure FileDownload
Sub New(ByVal URL As String, ByVal DestFilePath As String)
Me.URL = URL
Me._percent = 0
Me.DownloadSize = Net.WebRequest.Create(Me.URL).GetResponse.ContentLength
Me.DownloadedSize = 0
Me.Percent = 0
Me.DestinationFile = DestFilePath
Me.client = New Net.WebClient
End Sub
Sub StartDownload()
client.DownloadFileAsync(New Uri(Me.URL), Me.DestinationFile)
End Sub
Sub StopDownload(ByVal DeleteFile As Boolean)
On Error Resume Next
Me.client.CancelAsync()
If DeleteFile = True And System.IO.File.Exists(Me.DestinationFile) Then
SetAttr(Me.DestinationFile, FileAttribute.Normal)
System.IO.File.Delete(Me.DestinationFile)
Me.DownloadedSize = 0
End If
Me.Percent = 0
End Sub
Private _percent As Single
Public Property Percent() As Single
Get
If System.IO.File.Exists(Me.DestinationFile) And Me.DownloadSize <> 0 Then
Me._percent = Me.DownloadedSize * 100 / Me.DownloadSize
Else
Me._percent = 0
End If
Return Me._percent
End Get
Set(ByVal value As Single)
Me._percent = value
End Set
End Property
Private _DownloadedSize As Long
Public Property DownloadedSize() As Long
Get
Try
Me._DownloadedSize = New System.IO.FileInfo(Me.DestinationFile).Length
Catch
Me._DownloadedSize = 0
End Try
Return Me._DownloadedSize
End Get
Set(ByVal value As Long)
Me._DownloadedSize = value
End Set
End Property
Private client As Net.WebClient
Public DestinationFile As String
Public URL As String
Public DownloadSize As Long
End Structure
It all seems to work fine using the following thread to download a file:
Code:
d = New FileDownload("http://www.myurl.com/url/to/download.exe", My.Computer.FileSystem.SpecialDirectories.Desktop & "\download.exe")
d.StartDownload()
Do While d.DownloadedSize < d.DownloadSize
ProgressbarAdapter(d.Percent, d.DownloadedSize & "/" & d.DownloadSize & " (" & d.Percent & "%)")
Threading.Thread.Sleep(200)
Loop
Now my big problem:
The second time I download the file, the file is made but the downloaded bytes stay 0. I carefully delete the file and then start it again. Somehow it can't download the file, but no error is given. Only after a while it crashes. 
If I then restart it, it just downloads the file. 
Soo...what is the reason I can't download the same file to the same location twice while the program is running?
This is really a weird bug 
EDIT:
It ALWAYS happens when twice downloading the same file. Changing the output file won't solve it. Really need help at this point.
Last edited by bergerkiller; May 25th, 2010 at 02:12 PM.
-
May 25th, 2010, 06:46 PM
#2
Re: Download structure fails
The first thing you need to do is to get rid of that On Error Resume Next and never use it again. If you believe that an exception can reasonably be thrown in your code then use a Try...Catch block to catch that exception specifically.
Secondly, I would suggest that that type should be a class rather than a structure. Look at the .NET Framework and the types it contains and consider what's a class and what's a structure. Any type with as much functionality as yours would be a class.
Once you've made those changes, your issue will probably either go away or you'll have a better idea of exactly what the cause is.
-
May 25th, 2010, 10:13 PM
#3
Re: Download structure fails
You can look in my signature for a Download Managing System and use it/borrow code from it.
-
May 26th, 2010, 06:58 AM
#4
Thread Starter
Fanatic Member
Re: Download structure fails
Yes I know of the error resume next, thats why I only use it when I have multiple commands that HAVE to be executed. If I put it all in one try block, and the first delete command fails, it doesnt continue wit hthe other stuff.
Just a way to prevent placing every command in a try block 
Andd...I just found out it isn't related to my structure.
I made a download thread without my structure (using a webclient), and it fails the second time I start.
I think the webclient can only download a file once...
Any other suggestions to download files?
-
May 26th, 2010, 04:26 PM
#5
Re: Download structure fails
Did you look in my signature?
-
May 26th, 2010, 05:55 PM
#6
Re: Download structure fails
On Error Resume Next simply ignores errors and continues. If you ignore an error, how do you expect to fix it? Use proper error handling and, when you catch an exception, you can diagnose the problem and fix it. While debugging at least, no error handling at all is better than On Error Resume Next.
-
May 30th, 2010, 04:58 AM
#7
Thread Starter
Fanatic Member
Re: Download structure fails
I fixed all problems already. It wasn't faulty error handling, I forgot to close a "getresponse" reader, causing the current stream to remain active. Trying to get the response from an active stream is impossible, causing a time-out.
This was the line causing the trouble:
Me.DownloadSize = Net.WebRequest.Create(Me.URL).GetResponse.ContentLength
The response was embedded, so it was impossible to close it. I had to give the response his own variable and close that.
I changed my structure to a class, for everyone interested, here is my (awesome) DownloadManager class for all your download needs 
Code:
Public Class DownloadManager
Sub New(ByVal URL As String, ByVal DestPath As String)
Me.URL = URL
Me.DestFileName = DestPath
End Sub
Public URL As String = ""
Private dfln As String = ""
Private Paused As Boolean = False
Private Downloading As Boolean = False
Private dledsize As Long = 0
Private tldlsize As Long = 0
Private dlfin As Boolean = False
Private etime As Long
Private ta As New Stopwatch
Private stopdl As Boolean = False
Public ReadOnly Property HasFinished() As Boolean
Get
Return dlfin
End Get
End Property
Public Property DestFileName() As String
Get
Return dfln
End Get
Set(ByVal value As String)
If Me.Downloading = False Then dfln = value
End Set
End Property
Public ReadOnly Property IsDownloading() As Boolean
Get
Return Downloading
End Get
End Property
Public ReadOnly Property IsPaused() As Boolean
Get
Return Paused
End Get
End Property
Public ReadOnly Property DownloadedSize() As SizeMeasure
Get
Return New SizeMeasure(dledsize)
End Get
End Property
Public ReadOnly Property TotalDownloadSize() As SizeMeasure
Get
If tldlsize = 0 Then
Dim ws As Net.WebResponse = Net.WebRequest.Create(Me.URL).GetResponse
Me.tldlsize = ws.ContentLength
ws.Close()
End If
Return New SizeMeasure(tldlsize)
End Get
End Property
Public ReadOnly Property Percentage() As Single
Get
If Me.tldlsize > 0 Then
Dim ti As Integer = dledsize * 1000 / tldlsize
Return ti / 10
Else
Return 0
End If
End Get
End Property
Public ReadOnly Property DownloadSpeed() As SpeedMeasure
Get
If etime <> 0 And Me.Downloading = True And Me.Paused = False Then
Return New SpeedMeasure(dledsize * 1000 / etime)
Else
Return New SpeedMeasure(0)
End If
End Get
End Property
Public ReadOnly Property ElapsedTime() As TimeMeasure
Get
Return New TimeMeasure(etime)
End Get
End Property
Public ReadOnly Property RemainingTime() As TimeMeasure
Get
If Me.Paused = False And Me.Downloading = True Then
Dim remainingbytes As Long = Me.tldlsize - Me.dledsize
Dim speed As Long = DownloadSpeed.BAS
If speed = 0 Then speed = 1
Return New TimeMeasure(remainingbytes * 1000 / speed)
Else
Return New TimeMeasure(0)
End If
End Get
End Property
Public Structure TimeMeasure
Sub New(ByVal Msecs As Long)
LoadTime(Msecs)
End Sub
Public Sub LoadTime(ByVal MiliSeconds As Long)
If MiliSeconds < 0 Then MiliSeconds = 0
Me.TotalMiliSeconds = MiliSeconds
Me.Hours = Int(MiliSeconds / 3600000)
Me.Minutes = Int(MiliSeconds / 60000) - Me.Hours * 3600
Me.Seconds = Int(MiliSeconds / 1000) - Me.Minutes * 60 - Me.Hours * 3600
Dim hstr As String = Me.Hours
Dim mstr As String = Me.Minutes
Dim sstr As String = Me.Seconds
If hstr.Length = 1 Then hstr = "0" & hstr
If mstr.Length = 1 Then mstr = "0" & mstr
If sstr.Length = 1 Then sstr = "0" & sstr
Me.TimeStringHMS = hstr & ":" & mstr & ":" & sstr
If Me.Hours > 0 Then
Me.TimeStringS = Int(MiliSeconds / 360000) & " hours"
ElseIf Me.Minutes > 0 Then
Me.TimeStringS = Int(MiliSeconds / 60000) & " minutes"
Else
Me.TimeStringS = Int(MiliSeconds / 1000) & " seconds"
End If
End Sub
Public TimeStringHMS As String
Public TimeStringS As String
Public TotalMiliSeconds As Long
Public Seconds As Long
Public Minutes As Long
Public Hours As Long
End Structure
Public Structure SpeedMeasure
Sub New(ByVal BAS As Long)
LoadSpeed(BAS)
End Sub
Public Sub LoadSpeed(ByVal BAS As Long)
Me.BAS = BAS
Me.KBAS = BAS / 1000
Me.MBAS = BAS / 1000000
If BAS > 1000000 Then
Me.SpeedString = Me.MBAS & " MB/s"
ElseIf BAS > 1000 Then
Me.SpeedString = Me.KBAS & " KB/s"
Else
Me.SpeedString = Me.BAS & " B/s"
End If
End Sub
Public SpeedString As String
Public BAS As Long
Public KBAS As Long
Public MBAS As Long
End Structure
Public Structure SizeMeasure
Sub New(ByVal Bytes As Long)
LoadSize(Bytes)
End Sub
Public Sub LoadSize(ByVal Bytes As Long)
Me.Bytes = Bytes
Me.KBytes = Bytes / 1000
Me.MBytes = Bytes / 1000000
Me.GBytes = Bytes / 1000000000
If Bytes > 1000000000 Then
SizeString = Me.GBytes & " GB"
ElseIf Bytes > 1000000 Then
SizeString = Me.MBytes & " MB"
ElseIf Bytes > 1000 Then
SizeString = Me.KBytes & " KB"
Else
SizeString = Me.Bytes & " bytes"
End If
End Sub
Public SizeString As String
Public Bytes As Long
Public KBytes As Long
Public MBytes As Long
Public GBytes As Long
End Structure
Private t As Threading.Thread
Public Sub StartDownload()
If Me.Downloading = False Then Me.Paused = False
If Me.Paused = False And Me.Downloading = False Then
Try
t = New Threading.Thread(AddressOf DownLoadProcess)
t.IsBackground = True
t.Start()
Catch ex As Exception
MsgBox(ex.Message & vbCrLf & vbCrLf & "Failed to start your download.", MsgBoxStyle.Critical)
End Try
Else
Me.Paused = False
End If
End Sub
Public Sub PauseDownload()
Me.Paused = True
End Sub
Public Sub StopDownload()
Me.stopdl = True
End Sub
Private Sub DownLoadProcess()
Try
Me.Downloading = True
Me.dlfin = False
Me.dledsize = 0
If System.IO.File.Exists(Me.DestFileName) Then
SetAttr(Me.DestFileName, FileAttribute.Normal)
System.IO.File.Delete(Me.DestFileName)
End If
Dim ws As Net.WebResponse = Net.WebRequest.Create(Me.URL).GetResponse
Me.tldlsize = ws.ContentLength
If Me.tldlsize > 0 Then
Dim str As IO.Stream = ws.GetResponseStream()
Dim inBuf(10000000) As Byte
Dim bytesToRead As Integer = Me.tldlsize
Dim fstr As New IO.FileStream(Me.DestFileName, IO.FileMode.OpenOrCreate, IO.FileAccess.Write)
'Dim lastw As Long = 0
Dim t As New Stopwatch
Dim oldet As Long = 0
While bytesToRead > 0
If Me.stopdl = True Then Exit While
If Me.Paused = False Then
t.Start()
oldet = etime
Dim count As Long = 10000000
If bytesToRead < 10000000 Then count = bytesToRead
Dim n As Integer = str.Read(inBuf, 0, count)
If n = 0 Then Exit While
Me.dledsize += n
bytesToRead -= n
fstr.Write(inBuf, 0, n)
etime = t.ElapsedMilliseconds
Else
t.Stop()
End If
End While
t.Stop()
etime = t.ElapsedMilliseconds
fstr.Close()
ws.Close()
str.Close()
Else
MsgBox("Failed to start your download because the link is invalid.", MsgBoxStyle.Critical)
End If
Catch ex As Exception
MsgBox("Failed to start your download. " & vbCrLf & vbCrLf & ex.Message, MsgBoxStyle.Critical)
End Try
If Me.stopdl = True Then
Try
System.IO.File.Delete(Me.DestFileName)
Catch
End Try
End If
Me.stopdl = False
Me.Downloading = False
Me.dlfin = True
End Sub
End Class
It has all features you would possibly need: download speed, size and downloaded size, percentage, remaining and elapsed download time, pause download feature, and all with special enhancements for displaying speed, time and size.
Last edited by bergerkiller; May 30th, 2010 at 05:06 AM.
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|