Click here to Skip to main content
Click here to Skip to main content
Go to top

VB.NET Background File Downloader

, 20 May 2009
Rate this:
Please Sign up or sign in to vote.
A multithreaded file downloader with progress details, speed info and more
fileDownloader-downloading.gif

Introduction

This class enables you to easily download multiple files in the background (via a separate thread), and will provide information about the amount of downloaded data, the percentage of completion, and the download speed. On top of this, you can cancel downloading, pause it, and of course also resume. Note that there is also a C# implementation of this class available. 

Background 

I started working on this class after someone on a programming help forum asked how to best download files in the background. I got a lot of ideas and based part of my code on the Downloading Files in .NET with all Information article, by Carmine_XX. This class adds multiple file support, logic/layout abstraction and is designed to be easy to use.

Using the Code 

Once you added the class to your project, you should be able to access it via the namespace Bn.Classes. You can of course adapt the namespace to your own preferences or delete it altogether.  

The first thing you need to do when using this class is (logically) create a new instance, and then add the files you want to download. You'll also need to set the local directory to which you want to download. This is pretty straight forward.

' Creating a new instance of a FileDownloader
Private WithEvents downloader As New FileDownloader
' A simple implementation of setting the directory path, 
' adding files from a textbox and starting the download
Private Sub btnStart_Click(ByVal sender As System.Object, _
	ByVal e As System.EventArgs) Handles btnStart.Click
    Dim openFolderDialog As New FolderBrowserDialog
    With downloader
        If openFolderDialog.ShowDialog() = Windows.Forms.DialogResult.OK Then
            .Files.Clear()
            .LocalDirectory = openFolderDialog.SelectedPath
            For Each path As String In txtFilesToDownload.Lines
           ' The FileInfo structure will parse your path, 
	  ' and split it to the path itself and the file name, 
	  ' which will both be available for you
                .Files.Add(New FileDownloader.FileInfo(path))
            Next
            .Start()
        End If
    End With
End Sub

The code needed to then pause, resume or cancel the downloads couldn't be simpler:

Private Sub btnPauze_Click(ByVal sender As System.Object, _
		ByVal e As System.EventArgs) Handles btnPauze.Click
    ' Pause the downloader
    downloader.Pause()
End Sub
Private Sub btnResume_Click(ByVal sender As System.Object, _
		ByVal e As System.EventArgs) Handles btnResume.Click
    ' Resume the downloader
    downloader.Resume()
End Sub 
Private Sub btnStop_Click(ByVal sender As System.Object, _
		ByVal e As System.EventArgs) Handles btnStop.Click
    ' Stop the downloader
    ' Note: This will not be instantaneous - the current requests need to 
    ' be closed down, and the downloaded files need to be deleted
    downloader.Stop()
End Sub 

The downloader also provides a few properties to indicate its current state: IsBusy, IsPaused, CanStart, CanStop, CanPause and CanResume (all booleans). Here you have an example of how to use these to set your interface:

' This event is fired every time the paused or busy state is changed, 
' and used here to set the controls of the interface
Private Sub downloader_StateChanged() _
    Handles downloader.StateChanged 'This is equal to: Handles 
                       'downloader.IsBusyChanged, downloader.IsPausedChanged
    ' Setting the buttons
    btnStart.Enabled = downloader.CanStart
    btnStop.Enabled = downloader.CanStop
    btnPauze.Enabled = downloader.CanPause
    btnResume.Enabled = downloader.CanResume

    ' Enabling or disabling the setting controls
    txtFilesToDownload.ReadOnly = downloader.IsBusy
    cbUseProgress.Enabled = Not downloader.IsBusy
End Sub	

This is the demo code to display the progress information:

' Occurs every time a block of data has been downloaded, 
' and can be used to display the progress with
' Note that you can also create a timer, and display the progress 
' every certain interval
' Also note that the progress properties return a size in bytes, 
' which is not really user friendly to display
' The FileDownloader class provides shared functions to format these 
' byte amounts to a more readable format, either in binary or decimal notation
Private Sub downloader_ProgressChanged() Handles downloader.ProgressChanged
    pBarFileProgress.Value = CInt(downloader.CurrentFilePercentage)
    lblFileProgressDetails.Text = String.Format("Downloaded {0} of {1} ({2}%)", _
		FileDownloader.FormatSizeBinary(downloader.CurrentFileProgress), _
		FileDownloader.FormatSizeBinary(downloader.CurrentFileSize), _
		downloader.CurrentFilePercentage) & String.Format(" - {0}/s", _
		FileDownloader.FormatSizeBinary(downloader.DownloadSpeed))
    If downloader.SupportsProgress Then
        pBarTotalProgress.Value = CInt(downloader.TotalPercentage)
        lblTotalProgressDetails.Text = _
		String.Format("Downloaded {0} of {1} ({2}%)", _
		FileDownloader.FormatSizeBinary(downloader.TotalProgress), _
		FileDownloader.FormatSizeBinary(downloader.TotalSize), _
		downloader.TotalPercentage)
    End If
End Sub 

Another noteworthy snippet of code is how to set the SupportsProgress property.

' Setting the SupportsProgress property - 
' if set to false, no total progress data will be available!
Private Sub cbUseProgress_CheckedChanged(ByVal sender As System.Object, _
		ByVal e As System.EventArgs) Handles cbUseProgress.CheckedChanged
    downloader.SupportsProgress = cbUseProgress.Checked
End Sub 

When the SupportProgress property is set to true, the file sizes will be calculated before any download is started. This can take a while, definitely when you have a large number of files. The FileDownloader class fires an event every time it starts checking the size of a file, which can be used to display the progress.

' Show the progress of file size calculation
Private Sub downloader_CalculationFileSize(ByVal sender As Object, _
	ByVal fileNumber As Int32) Handles downloader.CalculatingFileSize
    lblStatus.Text = String.Format("Calculating file sizes - _
		file {0} of {1}", fileNumber, downloader.Files.Count)
End Sub

Points of Interest  

When I started working on this class, I assumed it would be ready after working on it for a day. I ran into some problems though, involving a wrong assumption I had about multithreading, and the fact that you can only have two open HttpWebResponses at the same time. Before I created this class, I was oblivious to the fact that objects get locked and can't always be set via all threads without the proper extra code. I also never used the ReportProgress event of the BackGroundWorker. After creating this class, I did some more reading on multithreading to get a better grip on it, and I can recommend the following series of articles: Beginners Guide To Threading In .NET Part 1 of n. I hope this article will both help other people out, and receive some critic feedback on how to improve the class itself.

I'm hoping to implement some more features soon, including cancellation without deleting the files and the option to resume downloading afterwards, and the ability to download multiple files simultaneously, on separate threads. 

History

  • May 20th 2009: Published version 1.0.3 and updated this article 
  • April 30th 2009: Published version 1.0.2 on my forums (added PackageSize and StopWatchCyclesAmount properties) 
  • April 22nd 2009: Published the first version of this article 
  • April 21st 2009: Published the class
    • For the code this is based upon (can be seen as an older version), see this article.

References

  • Dutch support for this class can be found here.
  • If I have only slightly updated code, I won't update this article and only publish it here.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)

Share

About the Author

Jeroen De Dauw
Software Developer
Belgium Belgium
I am a free and open source software enthusiast and freelance software developer with multiple years of experience in both web and desktop development. Currently my primarily focus is on MediaWiki and Semantic MediaWiki work. I'm in the all time top 10 MediaWiki comitters and am one of the WikiWorks consultants. You can contact me at jeroendedauw at gmail for development jobs and questions related to my work.
 
More info can be found on my website [0] and my blog [1]. You can also follow me on twitter [2] and identi.ca [3].
 
[0] http://www.jeroendedauw.com/
[1] http://blog.bn2vs.com/
[2] https://twitter.com/#!/JeroenDeDauw
[3] http://identi.ca/jeroendedauw
Follow on   Twitter

Comments and Discussions

 
QuestionTHANKS!!!! PinmemberMember 1050394123-May-14 6:12 
Questionrestart Pinmembermikehood20066-Apr-14 9:38 
Questionhow can download a file from password protected host ? Pinmemberlight2536025-Mar-13 12:53 
QuestionInfinity % PinmemberPaul720-Feb-13 16:34 
QuestionProblem with the ProgressChanged Event PinmemberPaul78-Feb-13 10:27 
AnswerRe: Problem with the ProgressChanged Event PinmemberPaul720-Feb-13 16:32 
BugHuge problem with THE SPEED PinmemberMember 847446029-Sep-12 13:03 
GeneralRe: Huge problem with THE SPEED Pinmemberwebflashing11-Oct-12 14:57 
GeneralRe: Huge problem with THE SPEED [modified] PinmemberMember 847446018-Oct-12 6:49 
GeneralRe: Huge problem with THE SPEED Pinmemberrevno19-Jan-13 3:49 
QuestionSimpleDownloadFile.suo PinmemberTrizarian11-Sep-12 14:13 
Generalnot working Pinmemberstefanz9227-Jun-12 2:26 
it only creates the files but its not downloading am i doing something wrongCry | :((
 
i now know the problem its not downloading .txt files wy?
GeneralRe: not working PinmemberFusionOz19-Aug-12 16:13 
QuestionWith File Size Pinmemberudnsofyan22-Feb-12 19:15 
Questionif use datagridview? Pinmemberfeatrick14-Nov-11 1:25 
GeneralMy vote of 5 PinmemberАslam Iqbal18-Jan-11 0:48 
QuestionAdding a class PinmemberJames Milligan16-Aug-10 22:25 
AnswerRe: Adding a class PinmemberJames Milligan16-Aug-10 22:28 
AnswerRe: Adding a class PinmemberFusionOz19-Aug-12 14:50 
GeneralGood article PinmemberLloyd Atkinson10-Aug-10 23:54 
GeneralGreat but eating my CPU... Pinmemberpimb210-Jul-09 4:20 
GeneralRe: Great but eating my CPU... Pinmemberbn2vs14-Jul-09 12:26 
QuestionWhat if i Want to download from mediafire ?? Pinmembergk874-Jul-09 9:08 
AnswerRe: What if i Want to download from mediafire ?? Pinmemberbn2vs14-Jul-09 12:22 
QuestionHow organize the tool work PinmemberAmirtich25-May-09 4:40 
AnswerRe: How organize the tool work Pinmemberbn2vs25-May-09 21:54 
GeneralRe: How organize the tool work PinmemberAmirtich26-May-09 1:59 
Generalgood article. PinmemberDonsw18-May-09 5:18 
GeneralRe: good article. Pinmemberbn2vs18-May-09 5:44 
GeneralRe: good article. PinmemberDonsw18-May-09 11:54 
GeneralRe: good article. Pinmemberbn2vs20-May-09 7:37 
GeneralRe: good article. PinmemberDonsw21-May-09 2:22 
Questioncredential setting Pinmemberpekatete15-May-09 16:01 
AnswerRe: credential setting Pinmemberbn2vs18-May-09 5:39 
GeneralRe: credential setting PinmemberAmirtich25-May-09 4:19 
GeneralRe: credential setting Pinmemberbn2vs25-May-09 21:56 
GeneralBITS service Pinmemberxlg4-May-09 22:34 
GeneralRe: BITS service Pinmemberbn2vs6-May-09 4:35 
GeneralC# Implementation Pinmemberbn2vs2-May-09 5:51 
GeneralSome updates Pinmemberbn2vs25-Apr-09 12:09 
GeneralError Report PinmemberAnt210023-Apr-09 2:53 
GeneralRe: Error Report Pinmemberbn2vs23-Apr-09 3:16 
GeneralRe: Error Report PinmemberAnt210023-Apr-09 3:29 
GeneralRe: Error Report Pinmemberbn2vs23-Apr-09 4:35 
GeneralRe: Error Report PinmemberAnt210023-Apr-09 4:47 
GeneralRe: Error Report Pinmemberbn2vs23-Apr-09 6:12 
GeneralRe: Error Report PinmemberAnt210023-Apr-09 7:57 
GeneralGood Idea and Good Work Pinmembersam.hill22-Apr-09 18:22 
GeneralRe: Good Idea and Good Work Pinmemberbn2vs23-Apr-09 3:28 
GeneralIncorrect category Pinmemberzennie22-Apr-09 10:59 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140916.1 | Last Updated 20 May 2009
Article Copyright 2009 by Jeroen De Dauw
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid