实现断点续传的FTP下载类(支持多线程多任务下载)

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.IO;
using System.Net;

namespace RSGIS.FTPClient
{

    public class MultiFtpService
    {
        #region variable

        private string _Server;//服务器地址
        private string _UserName;//用户名
        private string _Password;//密码
        private string _FileUrl;//文件地址
        private string _SavePath;//保存路经        
        Thread _Thread;
        private int _TaskIndex;
        private int _ThreadIndex;

        private int FileSpeed;        // 实时下载速度

        private FtpWebRequest ftpRequest = null;
        private FtpWebResponse ftpResponse = null;
        private Stream ftpStream = null;
        private int bufferSize = 2048;
        private int highestPercentageReached = 0;

        public delegate void DelegateDisplayProgress(int taskindex, int progress);
        public DelegateDisplayProgress WorkMethod;

        public delegate void DelegateDisplayFileSpeed(int taskindex, string speed);
        public DelegateDisplayFileSpeed FileSpeedMethod;

        #endregion

        #region Constructor

        public MultiFtpService(string server, string username, string password, int taskIndex, int threadIndex, string fileUrl, string savePath)
        {
            _Server = server;
            _UserName = username;
            _Password = password;
            _FileUrl = fileUrl;
            _SavePath = savePath;
            _TaskIndex = taskIndex;
            _ThreadIndex = threadIndex;
        }

        #endregion

        #region Functions
        //开始
        public void Start()
        {
            long fileSize = GetLength();
            _Thread = new Thread(() => { TheadDownload(_FileUrl, _SavePath, _TaskIndex, _ThreadIndex, fileSize); });
            _Thread.Start();
        }
        /// <summary>
        /// 暂停线程
        /// </summary>
        public void Stop()
        {
            _Thread.Suspend();
        }
        // 恢复线程
        public void continues()
        {
            _Thread.Resume();
        }
        //获取文件长度
        private long GetLength()
        {
            Ftp ftpclient = new Ftp(_Server, _UserName, _Password);
            long fileSize = ftpclient.getFileSize(_FileUrl);
            ftpclient = null;
            return fileSize;
        }
        /// <summary>
        /// 下载
        /// </summary>
        /// <param name="remoteFile"></param>
        /// <param name="localFile"></param>
        /// <param name="taskindex"></param>
        /// <param name="threadindex"></param>
        /// <param name="fileSize"></param>
        private void TheadDownload(string remoteFile, string localFile, int taskindex, int threadindex, long fileSize)
        {
            try
            {
                //续传
                if (File.Exists(localFile))
                {
                    FileInfo file = new FileInfo(localFile);
                    int locSize = Convert.ToInt32(file.Length);
                    if (locSize.ToString() != fileSize.ToString())
                    {
                        Uri FTPUri = new Uri(_Server + "/" + remoteFile);
                        RestartDownloadFromServer(taskindex, localFile, FTPUri, file.Length, fileSize);
                    }
                }
                else
                {
                    // Create Request
                    ftpRequest = (FtpWebRequest)FtpWebRequest.Create(_Server + "/" + remoteFile);
                    ftpRequest.Credentials = new NetworkCredential(_UserName, _Password);
                    ftpRequest.UseBinary = true;
                    ftpRequest.UsePassive = true;
                    ftpRequest.KeepAlive = true;
                    ftpRequest.Proxy = GlobalProxySelection.GetEmptyWebProxy();
                    // Request Type
                    ftpRequest.Method = WebRequestMethods.Ftp.DownloadFile;
                    // Get Response
                    ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
                    // Get server response stream 
                    ftpStream = ftpResponse.GetResponseStream();
                    FileStream localFileStream = new FileStream(localFile, FileMode.Create);
                    // Buffer for downloaded data
                    byte[] byteBuffer = new byte[bufferSize];
                    int bytesRead = ftpStream.Read(byteBuffer, 0, bufferSize);
                    // Download File
                    int fileSizes = Convert.ToInt32(fileSize);
                    try
                    {
                        while (bytesRead > 0)
                        {
                            localFileStream.Write(byteBuffer, 0, bytesRead);
                            bytesRead = ftpStream.Read(byteBuffer, 0, bufferSize);
                            int Complete = Convert.ToInt32(fileSizes) - bytesRead;
                            double Fcompletes = Convert.ToDouble(Complete) / Convert.ToDouble(fileSize);
                            double x = 1;
                            double Fcomplete = x - Fcompletes;
                            fileSizes = Complete;
                            if (Fcomplete * 100 > highestPercentageReached)
                            {
                                WorkMethod(taskindex, Convert.ToInt32(Fcomplete * 100));
                                string speed = SizeConversion(Convert.ToInt64(bytesRead / 0.01));
                                FileSpeedMethod(taskindex, speed);
                                
                            }
                        }
                        FileInfo file = new FileInfo(localFile);
                        int locSize = Convert.ToInt32(file.Length);
                        if (locSize.ToString() != fileSizes.ToString())
                        {
                            Uri FTPUri = new Uri(_Server + "/" + remoteFile);
                            RestartDownloadFromServer(taskindex, localFile, FTPUri, file.Length, fileSize);
                        }
                    }
                    catch (Exception ex)
                    {
                        throw new Exception(ex.Message);
                    }
                    localFileStream.Close();
                    ftpStream.Close();
                    ftpResponse.Close();
                    ftpRequest = null;
                    WorkComplete();
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            //catch { }
        }
        //断点续传
        private bool RestartDownloadFromServer(int taskindex, string fileName, Uri serverUri, long offset, long fileSize)
        {
            if (serverUri.Scheme != Uri.UriSchemeFtp)
            {
                return false;
            }

            // 获取ftp
            FtpWebRequest request = (FtpWebRequest)WebRequest.Create(serverUri);
            request.Credentials = new NetworkCredential(_UserName, _Password);
            request.UseBinary = true;
            request.UsePassive = true;
            request.KeepAlive = true;
            request.Proxy = GlobalProxySelection.GetEmptyWebProxy();
            // Request Type
            request.Method = WebRequestMethods.Ftp.DownloadFile;
            request.ContentOffset = offset;
            FtpWebResponse response = null;
            try
            {
                response = (FtpWebResponse)request.GetResponse();
            }
            catch (WebException e)
            {
                Console.WriteLine(e.Status);
                Console.WriteLine(e.Message);
                return false;
            }
            // 获取流
            ftpStream = response.GetResponseStream();
            //StreamReader reader = new StreamReader(newFile);
            //string newFileData = reader.ReadToEnd();
            FileStream localFileStream = new FileStream(fileName, FileMode.Append);
            // Buffer for downloaded data
            byte[] byteBuffer = new byte[bufferSize];
            int bytesRead = ftpStream.Read(byteBuffer, 0, bufferSize);

            // Download File
            int fileSizes = Convert.ToInt32(fileSize);
            try
            {
                while (bytesRead > 0)
                {
                    localFileStream.Write(byteBuffer, 0, bytesRead);
                    bytesRead = ftpStream.Read(byteBuffer, 0, bufferSize);
                    int Complete = Convert.ToInt32(fileSizes) - bytesRead;
                    double Fcompletes = Convert.ToDouble(Complete) / Convert.ToDouble(fileSize);
                    double x = 1;
                    double Fcomplete = x - Fcompletes;
                    fileSizes = Complete;
                    if (Fcomplete * 100 > highestPercentageReached)
                    {
                        Fcomplete = Fcomplete + offset / fileSize;
                        WorkMethod(taskindex, Convert.ToInt32(Fcomplete * 100));
                        string speed = SizeConversion(Convert.ToInt64(bytesRead / 0.01));
                        FileSpeedMethod(taskindex, speed);
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            //关闭流
            localFileStream.Close();
            ftpStream.Close();
            response.Close();
            request = null;
            WorkComplete();
            return true;
        }
        //完成
        public void WorkComplete()
        {
            MessageBox.Show("文件下载成功", "Success", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        }

        /// <summary>
        /// 文件大小换算
        /// </summary>
        /// <param name="bytes">文件长度</param>
        /// <returns></returns>
        private string SizeConversion(long bytes)
        {
            int unit = 1024;
            if (bytes < unit) return bytes + " B";
            int exp = (int)(Math.Log(bytes) / Math.Log(unit));
            return String.Format("{0:F1} {1}B", bytes / Math.Pow(unit, exp), "KMGTPE"[exp - 1]);
        }
        #endregion
    }
}