Multi-part Download with Multiple Threads
This topic shows you how to use multiple threads to connect to an FTP server and download a file. First, we need to define a class which contains information about the file, and the threads. In this example, it's named GlobalInfo. And then we define a class for Ftp Threads, it's named FtpThread. Finally, in the main routine, we create and start 3 threads to download the parts of the file. As a result, the download speed is improved if the file is large. We take advantage of the GetDownloadStream method with the following example code:
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Atp.Net;
using System.Threading;
namespace Samples
{
class GlobalInfo
{
// Maintain some information about the threads.
public int CompletedThreads;
public int Threads;
public ManualResetEvent Event;
public byte[][] Streams;
public long Length = -1;
public int BlockSize;
public bool Finish;
}
class FtpThread
{
int _offset;
int _blockSize;
GlobalInfo _info;
Ftp _client;
int _index;
public FtpThread(GlobalInfo info, int index)
{
_info = info;
_index = index;
}
public void Start()
{
const string remoteFile = "/pub/test.zip";
_client = new Ftp();
_client.Connect("atp-inc.net");
_client.Authenticate("test", "test");
byte[] buf;
lock (_info)
{
if (_info.Length == -1)
{
// Get file length.
_info.Length = _client.GetFileLength(remoteFile);
// Calculate block size.
_info.BlockSize = (int)(_info.Length / _info.Threads);
_info.Streams = new byte[_info.Threads][];
}
// Calculate offset.
_offset = _info.BlockSize * _index;
_blockSize = (int)((_index == _info.Threads - 1) ? (_info.Length - _index * _info.BlockSize) : _info.BlockSize);
buf = new byte[_blockSize];
_info.Streams[_index] = buf;
}
// Get download stream.
Stream downloader = _client.GetDownloadStream(remoteFile, SeekOrigin.Begin, _offset);
int count = 0;
// Download data.
while (true)
{
int size = (count + 4048 > _blockSize) ? (_blockSize - count) : 4048;
int read = downloader.Read(buf, count, size);
if (count + read >= _blockSize || read == 0)
break;
count += read;
}
downloader.Close();
_client.Disconnect();
lock (_info)
{
_info.CompletedThreads++;
if (_info.CompletedThreads == _info.Threads && !_info.Finish)
{
_info.Event.Set();
// All threads have completed.
// Combine
using (FileStream sw = System.IO.File.OpenWrite(@"c:\temp\test.zip"))
{
foreach (byte[] s in _info.Streams)
{
sw.Write(s, 0, (int)s.Length);
}
}
_info.Finish = true;
}
}
}
}
class MultiParts
{
static ManualResetEvent _event = new ManualResetEvent(false);
static Ftp client;
static void Main()
{
const int threads = 3;
// Use 3 threads to download a remote file to streams and then save the streams into a local file.
int offset = 0;
GlobalInfo ginfo = new GlobalInfo();
ginfo.Threads = threads;
ginfo.Event = _event;
for (int i = 0; i < threads; i++)
{
FtpThread fthread = new FtpThread(ginfo, i);
Thread th = new Thread(fthread.Start);
th.Start();
}
_event.WaitOne();
}
}
}
Click here to download the Ultimate FTP Component for .NET, or here to download the .NET CF version.
Copy Code