From comments below:
I made the class so it is easy to make a multi-downloading download client, and I like many small classes rather than a few huge ones, so I added this. One would hope that it isn't too hard to understand the coding with my unusual coding semantics. It is really here as a starting point for people looking to build a Download manager them selves. I tried to keep the coding simple so it is reasonably easy to understand. It is too easy for a beginner to see a huge class and not read it, just execute some of it's methods, I didn't want that to happen with this. I hoped it would be something that some one can read and learn some of the concepts of file downloads. It may not be a useful class on it's own but it should be educational.
A simple class that can be added to your program to add download functionality. It is very useful to me in my Podcatcher program. It uses Streams to download the files. The main variables that make this work are
private Stream strResponse;
private Stream strLocal;
private HttpWebRequest webRequest;
private HttpWebResponse webResponse;
strResponse is used to stream the data from the server into the application, this is then picked up by the
strLocal which is used to save the data to the disk. The
webResponse are used to negotiate the download with the server.
The main download method works by first asking the server to start sending the file by creating the
webRequest with the URL of the file like so:
webRequest = (HttpWebRequest)WebRequest.Create(fileURL);
There is then some credential negotiation which is set to the default, if you have credentials to the file then you would have to create them. Finally the server's response is saved in memory as
fileSize var is then set to this value so the program knows how many bytes it is downloading. The
fileSize var has to be a 64 bit integer so it can store the large numbers assoc. with the number of bytes in a file. If you KNOW you are going to be downloading files where the
fileSize in bytes can be stored in a smaller var then it is OK to change it, but I do not recommend it.
Once the code has negotiated with the server a
WebClient is then used to set the
strRepsonse to the file on the server. The code then creates a stream to the local disk, it uses the
filePATH which is now set to the file's path and contains the name and extension too due to the parsing that happens on creation. Once that is done the buffers and byte sizes are set and the code begins to read each byte from the server and write it to the disk.
Once that has done the code closes the two streams and claims it has done using a bool locally stored. You could use event handlers here to throw a new even if you wanted for download completion.
Using the Code
I tried to make this code perform well in MTAs (multi-threaded applications) so the start download function opens a new thread. If you don't want it to do this for example, it is created in a thread. And if you don't want nesting of threads, then it is easy to remove that.
Download dl = new Download("url", "path", "name");
I have built the class assuming that you are wanting to start the download immediately, so the creation method will run the
start() method to get the download going, but you could edit the class to start it when you want, by calling:
The instantiation also does some path stuff, getting the extension from the URL automatically, so don't add that to the name - it will look silly. E.g.: for, aDoc.txt.txt just use the URL of the file, the location it must be saved to, and the name without the extension.
There is also a stop function which may be helpful, it is cunningly called
Because this class is threaded already, you can get the current progress without pausing the operation to update the UI; I found this quite helpful. The progress is outputted as a percent by a public integer. There is also a string for the status that will display the current progress in the format "Downloaded " + BytesRead + " out of " + TotalBytes + " (" + PercentProgress + "%)", but that would be easy to change.
public string status;
public int progress;
Points of Interest
A very easy way of managing many downloads is to use a collection, I found this to be the easiest way of using the code. While I am sure an array would do the same, the collection has a little more functionality, and it is easy to add and remove downloads as needed.
I have had a few issues with some of the stop method calling. If you get that too, just replace the code in
thrDownload.Abort();. You could make the
thrDownload public too for some added control, although I doubt it is necessary to most users.
Something I also noticed while playing with the code is that it automatically resumes if a download is stopped - so you don't need to worry about crashes or pausing, just run
stop() to hold the download and running
start() with the same file name and url in place (use the same instantiated class for example) to resume the download.
Why use this code
I have made this code to be as efficient in threading as I can, it is very easy to start up a download with this and leave it going in the background. I also made it so it is easy to build a download manager (DLM). A simple List like
List<Download> dlList = new List<Download>();
is a great way to manage many downloads, it already contains the name, url, destination and completed percentage so is offering it's self to a DLM using some sort of UI. It would not be hard for the class to store things like descriptions or start times either, by making the constructor method look like this:
public string _Description;
public DateTime startedAt;
public Download(string url, string path, string name, string description)
filePATH = path + "\\" + getFilename(url, name);
fileURL = url;
_Description = description;
startedAt = DateTime.Now;
Most importantly it gives you a uniform starting point from where to start building any sort of download manager, or just to add some features from an existing app
Autoresume is a very nice feature too
- 12/12/2009 - Uploaded the article.
- 12/12/2009 - Added some more information about how the code works
- 12/12/2009 - Added "Why use this code" section
- 22/12/2009 - Added information about auto-resuming after a stop.