天天看點

ftp斷點下載下傳(多線程)

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

namespace SoulWorkerDownload
{
    /// <summary>
    /// FTP檔案上傳下載下傳
    /// </summary>
    public class FileUpDownload
    {

        #region 變量屬性

        private Thread m_thread_Download = null;

        /// <summary>
        /// Ftp伺服器ip
        /// </summary>
        private string FtpServerIP = string.Empty;
        /// <summary>
        /// Ftp 指定使用者名
        /// </summary>
        private string FtpUserID = string.Empty;
        /// <summary>
        /// Ftp 指定使用者密碼
        /// </summary>
        private string FtpPassword = string.Empty;

        /// <summary>
        /// 遠端檔案名
        /// </summary>
        private string remoteFileName = string.Empty;

        /// <summary>
        /// 本地檔案名
        /// </summary>
        private string localFileName = string.Empty;

        public string LocalFileName
        {
            get { return localFileName; }
            set {  localFileName = value; }
        }

        private MainForm mainform;


        /// <summary>
        /// 更新進度條
        /// </summary>
        public Action< long> updateProgress;

        #endregion

        #region 從FTP伺服器下載下傳檔案,指定本地路徑和本地檔案名

        public FileUpDownload(string IP, string userID, string userPassword,string targetFileName,string saveFileName,MainForm form)
        {
            FtpServerIP = IP;
            FtpUserID = userID;
            FtpPassword = userPassword;
            remoteFileName = targetFileName;
            localFileName = saveFileName;
            mainform = form;
        }

        public void StartSingleDownload()
        {
            m_thread_Download = new Thread(new ThreadStart(FtpDownloadFile));
            m_thread_Download.SetApartmentState(ApartmentState.STA);
            m_thread_Download.Priority = ThreadPriority.Highest;
            m_thread_Download.Start();
        }

        /// <summary>
        /// 停止下載下傳
        /// </summary>
        public void AbortSingleDownload()
        {
            if (m_thread_Download != null && m_thread_Download.IsAlive )
            {
                if (m_thread_Download.ThreadState == ThreadState.Suspended)
                    m_thread_Download.Resume();

                //if(Step.CURRENT_STEP != Step.State._ProcessState_Restart)
                    m_thread_Download.Abort();
            }
        }

        /// <summary>
        /// 暫停。挂起線程,或者如果線程已挂起,則不起作用
        /// </summary>
        /// <param name="_parameter"></param>
        public void SuspendSingleDownload()
        {
            if (m_thread_Download != null && m_thread_Download.IsAlive == true)
            {
                m_thread_Download.Suspend();
            }
        }

        public void ResumeSingleDownload()
        {
            bool isAlive = m_thread_Download.IsAlive;
            ThreadState state = m_thread_Download.ThreadState;

            if (m_thread_Download != null)
            {
                m_thread_Download.Resume();
            }
        }

        /// <summary>
        /// 判斷線程是否結束
        /// </summary>
        public bool IsAbortThreadOrStop()
        {
            bool isAbort = false;

            //bool alive = m_thread_Download.IsAlive;

            if (m_thread_Download == null)
                return true;


            if ((m_thread_Download.ThreadState & ThreadState.Aborted) != 0)
            {
                isAbort = true;
            }
            if (!m_thread_Download.IsAlive)
            {
                isAbort = true;
            }
            return isAbort;
        }

        
        /// <summary>
        /// 從FTP伺服器下載下傳檔案,指定本地路徑和本地檔案名
        /// </summary>
        /// <param name="remoteFileName">遠端檔案名</param>
        /// <param name="localFileName">儲存本地的檔案名(包含路徑)</param>
        /// <param name="updateProgress">報告進度的處理(第一個參數:總大小,第二個參數:目前進度)</param>
        /// <returns>是否下載下傳成功</returns>
        public  bool FtpDownload(string remoteFileName, string localFileName, Action<int, int> updateProgress = null)
        {
            FtpWebRequest reqFTP, ftpsize;
            Stream ftpStream = null;
            FtpWebResponse response = null;
            FileStream outputStream = null;
            try
            {
 
                outputStream = new FileStream(localFileName, FileMode.Create);
                if (FtpServerIP == null || FtpServerIP.Trim().Length == 0)
                {
                    throw new Exception("ftp下載下傳目标伺服器位址未設定!");
                }
                Uri uri = new Uri("ftp://" + FtpServerIP + "/" + remoteFileName);
                ftpsize = (FtpWebRequest)FtpWebRequest.Create(uri);
                ftpsize.UseBinary = true;
 
                reqFTP = (FtpWebRequest)FtpWebRequest.Create(uri);
                reqFTP.UseBinary = true;
                reqFTP.KeepAlive = false;
                
                ftpsize.Credentials = new NetworkCredential(FtpUserID, FtpPassword);
                reqFTP.Credentials = new NetworkCredential(FtpUserID, FtpPassword);
                
                ftpsize.Method = WebRequestMethods.Ftp.GetFileSize;
                FtpWebResponse re = (FtpWebResponse)ftpsize.GetResponse();
                long totalBytes = re.ContentLength;
                re.Close();
 
                reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
                response = (FtpWebResponse)reqFTP.GetResponse();
                ftpStream = response.GetResponseStream();
 
                //更新進度  
                if (updateProgress != null)
                {
                    updateProgress((int)totalBytes, 0);//更新進度條   
                }
                long totalDownloadedByte = 0;
                int bufferSize = 2048;
                int readCount;
                byte[] buffer = new byte[bufferSize];

                readCount = ftpStream.Read(buffer, 0, bufferSize);


                while (readCount > 0)
                {
                    totalDownloadedByte = readCount + totalDownloadedByte;
                    outputStream.Write(buffer, 0, readCount);
                    //更新進度  
                    if (updateProgress != null)
                    {
                        updateProgress((int)totalBytes, (int)totalDownloadedByte);//更新進度條   
                    }
                    readCount = ftpStream.Read(buffer, 0, bufferSize);
                }
                ftpStream.Close();
                outputStream.Close();
                response.Close();
                return true;
            }
            catch (Exception)
            {
                return false;
                throw;
            }
            finally
            {
                if (ftpStream != null)
                {
                    ftpStream.Close();
                }
                if (outputStream != null)
                {
                    outputStream.Close();
                }
                if (response != null)
                {
                    response.Close();
                }
            }
        }

        

        bool isShowIOError = false;
        /// <summary>
        /// 從FTP伺服器下載下傳檔案,指定本地路徑和本地檔案名(支援斷點下載下傳)
        /// </summary>
        /// <param name="remoteFileName">遠端檔案名</param>
        /// <param name="localFileName">儲存本地的檔案名(包含路徑)</param>
        /// <param name="ifCredential">是否啟用身份驗證(false:表示允許使用者匿名下載下傳)</param>
        /// <param name="size">已下載下傳檔案流大小</param>
        /// <param name="updateProgress">報告進度的處理(第一個參數:總大小,第二個參數:目前進度)</param>
        /// <returns>是否下載下傳成功</returns>
        public  bool FtpBrokenDownload(string remoteFileName, string tempLocalFileName, long size, Action<long> updateProgress = null)
        {
            bool isFinish = false;
            FtpWebRequest reqFTP, ftpsize;
            Stream ftpStream = null;
            FtpWebResponse response = null;
            FileStream outputStream = null;
            long totalBytes = 0;
            long totalDownloadedByte = size;

            try
            {
                Thread primaryThread = Thread.CurrentThread;
                //                 string name = "FtpDownload" + primaryThread.ManagedThreadId;
                //                 MessageBox.Show(name 
                if (FtpServerIP == null || FtpServerIP.Trim().Length == 0)
                {
                    throw new Exception("ftp下載下傳目标伺服器位址未設定!");
                }
                Uri uri = new Uri("ftp://" + FtpServerIP + "/" + remoteFileName);
                ftpsize = (FtpWebRequest)FtpWebRequest.Create(uri);
                ftpsize.UseBinary = true;
                ftpsize.ContentOffset = size;

                reqFTP = (FtpWebRequest)FtpWebRequest.Create(uri);
                reqFTP.UseBinary = true;
                reqFTP.KeepAlive = false;
                reqFTP.ContentOffset = size;
                ftpsize.Credentials = GetCredentials(); //new NetworkCredential(FtpUserID, FtpPassword);
                reqFTP.Credentials = GetCredentials();// new NetworkCredential(FtpUserID, FtpPassword);
                ftpsize.Method = WebRequestMethods.Ftp.GetFileSize;
                FtpWebResponse re = (FtpWebResponse)ftpsize.GetResponse();
                totalBytes = re.ContentLength;
                re.Close();
                if (size == totalBytes)
                {
                    return true;
                }
                else
                    Step.CURRENT_STEP = Step.State._ProcessState_Loading;

                reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
                response = (FtpWebResponse)reqFTP.GetResponse();
                ftpStream = response.GetResponseStream();


                int bufferSize = 2048;
                int readCount;
                byte[] buffer = new byte[bufferSize];
                readCount = ftpStream.Read(buffer, 0, bufferSize);
                using (outputStream = new FileStream(tempLocalFileName, FileMode.Append))
                {
                    while (readCount > 0)
                    {
                        outputStream.Write(buffer, 0, readCount);
                        totalDownloadedByte = readCount + totalDownloadedByte;

                        //更新進度  
                        if (updateProgress != null)
                        {
                            updateProgress(totalDownloadedByte);//更新進度條   
                        }
                        try
                        {
                            readCount = ftpStream.Read(buffer, 0, bufferSize);

                        }
                        catch
                        {
                            break;
                        }
                    }
                }

                try
                {
                    response.Close();
                    ftpStream.Close();
                }
                catch { }
                outputStream.Close();
                if (totalDownloadedByte == totalBytes)
                {
                    isFinish = true;
                }
            }
            catch(WebException e)
            {
                FtpWebResponse res = (FtpWebResponse)e.Response;
                string code = "下載下傳伺服器連接配接失敗,錯誤碼:" + res.StatusCode;
                MessageBox.Show(code);
            }
            catch (IOException e)
            {
                isShowIOError = true;
                MessageBox.Show(e.Message);
            }
            finally
            {
                try
                {

                    if (ftpStream != null)
                    {
                        ftpStream.Close();
                    }
                    if (outputStream != null)
                    {
                        outputStream.Close();
                    }
                    if (response != null)
                    {
                        response.Close();
                    }
                }
                catch { }
            }
            if (totalDownloadedByte == totalBytes)
            {
                isFinish = true;
            }
            return isFinish;
        }
 
        
        /// <summary>
        /// 從FTP伺服器下載下傳檔案,指定本地路徑和本地檔案名
        /// </summary>
        /// <param name="remoteFileName">遠端檔案名</param>
        /// <param name="localFileName">儲存本地的檔案名(包含路徑)</param>
        /// <param name="updateProgress">報告進度的處理(第一個參數:總大小,第二個參數:目前進度)</param>
        /// <param name="brokenOpen">是否斷點下載下傳:true 會在localFileName 找是否存在已經下載下傳的檔案,并計算檔案流大小</param>
        /// <returns>是否下載下傳成功</returns>
        //public static bool FtpDownloadFile(string remoteFileName, string localFileName, bool brokenOpen, Action<int, int> updateProgress = null)
        public void FtpDownloadFile()
        {
            long size0 = 0;
            long size1 = 0;

            if (File.Exists(localFileName))
            {
                using (FileStream outputStream = new FileStream(localFileName, FileMode.Open))
                {
                    size0 = outputStream.Length;
                }
            }

            //逾時2次内再重連
            while (!FtpBrokenDownload(remoteFileName, localFileName, size0, updateProgress))
            {
                if (Step.CURRENT_STEP != Step.State._ProcessState_Loading)
                {
                    AbortSingleDownload();
                    return;
                }
            
                if (File.Exists(localFileName))
                {
                    using (FileStream outputStream = new FileStream(localFileName, FileMode.Open))
                    {
                        size1 = outputStream.Length;
                    }
                }
                if (size1 == size0)
                {
                    //MessageBox.Show("下載下傳伺服器連接配接失敗,請檢查網絡并確定防火牆允許SoulWorkerDownload聯網!");
                    mainform.AppEnd();
                    return;
                }
                else
                {
                    size0 = size1;
                }
            }

        }
 
        #endregion

        #region ftp檔案工具類

        /// <summary>
        /// 檢查ftp上該檔案是否存在
        /// </summary>
        /// <param name="strFilename"></param>
        /// <returns></returns>
        public bool FtpFileExists()
        {
            try
            {
                long size = GetFileSize();
                if (size > 0)
                    return true;
                return false;
            }
            catch (Exception ex)
            {
                if (ex is WebException)
                {
                    if (ex.Message.Contains("550"))
                    {
                        return false;
                    }
                    else
                    {
                        throw;
                    }
                }
                else
                {
                    throw;
                }
            }
        }

        /// <summary>
        /// 擷取檔案的大小
        /// </summary>
        /// <param name="strFilename"></param>
        /// <returns></returns>
        public long GetFileSize()
        {
            long fileBytes = 0;
            FtpWebResponse re =null;
            try
            {
                if (FtpServerIP == null || FtpServerIP.Trim().Length == 0)
                {
                    throw new Exception("ftp下載下傳目标伺服器位址未設定!");
                }
                string uri = "ftp://" + FtpServerIP + "/" + remoteFileName;

                FtpWebRequest ftp = GetRequest(uri);
                ftp.Method = WebRequestMethods.Ftp.GetFileSize;
                re = (FtpWebResponse)ftp.GetResponse();
                fileBytes = re.ContentLength;
                re.Close();
            }
            catch (WebException ex)
            {
                if (!isShowIOError)
                {
                    FtpWebResponse res = (FtpWebResponse)ex.Response;
                    string code = "下載下傳伺服器連接配接失敗,錯誤碼:" + res.StatusCode;
                    MessageBox.Show(code);
                }
                mainform.AppEnd();
            }
            finally
            {
                if (re != null)
                    re.Close();
            }
            return fileBytes;
        }



        //請求檢視檔案夾
        private FtpWebRequest GetRequest(string strURI)
        {
            FtpWebRequest result = (FtpWebRequest)FtpWebRequest.Create(strURI);

            result.Credentials = GetCredentials();//建立請求

            result.KeepAlive = false;
            result.Timeout = 20000;
            result.UsePassive = false;

            return result;
        }

        private ICredentials GetCredentials()
        {
            return new NetworkCredential(FtpUserID, FtpPassword);
        }
        #endregion

    }

}