ftp 操作,支持断点续传或者继续下载。

1、ftpclient 类

  public class FTPClient:IDisposable
    {
        public static object _obj = new object();

        #region 构造函数
        /// <summary>
        /// 缺省构造函数
        /// </summary>
        public FTPClient()
        {
            _strRemoteHost = "";
            _strRemotePath = "";
            _strRemoteUser = "";
            _strRemotePass = "";
            _strRemotePort = 21;
            _bConnected = false;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        public FTPClient(string remoteHost, string remotePath, string remoteUser, string remotePass, int remotePort)
        {
            _strRemoteHost = remoteHost;
            _strRemotePath = remotePath;
            _strRemoteUser = remoteUser;
            _strRemotePass = remotePass;
            _strRemotePort = remotePort;
            Connect();
        }
        #endregion

        #region 字段
        private int _strRemotePort;
        private Boolean _bConnected;
        private string _strRemoteHost;
        private string _strRemotePass;
        private string _strRemoteUser;
        private string _strRemotePath;

        /// <summary>
        /// 服务器返回的应答信息(包含应答码)
        /// </summary>
        private string _strMsg;
        /// <summary>
        /// 服务器返回的应答信息(包含应答码)
        /// </summary>
        private string _strReply;
        /// <summary>
        /// 服务器返回的应答码
        /// </summary>
        private int _iReplyCode;
        /// <summary>
        /// 进行控制连接的socket
        /// </summary>
        private Socket _socketControl;
        /// <summary>
        /// 传输模式
        /// </summary>
        private TransferType _trType;
        /// <summary>
        /// 接收和发送数据的缓冲区
        /// </summary>
        private static int _BLOCK_SIZE = 512;
        /// <summary>
        /// 编码方式
        /// </summary>
        Encoding _ASCII = Encoding.UTF8;
        /// <summary>
        /// 字节数组
        /// </summary>
        Byte[] _buffer = new Byte[_BLOCK_SIZE];
        #endregion

        #region 属性
        /// <summary>
        /// FTP服务器IP地址
        /// </summary>
        public string RemoteHost
        {
            get
            {
                return _strRemoteHost;
            }
            set
            {
                _strRemoteHost = value;
            }
        }

        /// <summary>
        /// FTP服务器端口
        /// </summary>
        public int RemotePort
        {
            get
            {
                return _strRemotePort;
            }
            set
            {
                _strRemotePort = value;
            }
        }

        /// <summary>
        /// 当前服务器目录
        /// </summary>
        public string RemotePath
        {
            get
            {
                return _strRemotePath;
            }
            set
            {
                _strRemotePath = value;
            }
        }

        /// <summary>
        /// 登录用户账号
        /// </summary>
        public string RemoteUser
        {
            set
            {
                _strRemoteUser = value;
            }
        }

        /// <summary>
        /// 用户登录密码
        /// </summary>
        public string RemotePwd
        {
            set
            {
                _strRemotePass = value;
            }
        }

        /// <summary>
        /// 是否登录
        /// </summary>
        public bool Connected
        {
            get
            {
                return _bConnected;
            }
        }
        #endregion

        #region 链接
        /// <summary>
        /// 建立连接 
        /// </summary>
        public void Connect()
        {
            lock (_obj)
            {
                _socketControl = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPEndPoint ep = new IPEndPoint(IPAddress.Parse(RemoteHost), _strRemotePort);
                try
                {
                    _socketControl.Connect(ep);
                }
                catch (Exception)
                {
                    throw new IOException("不能连接ftp服务器");
                }
            }
            ReadReply();
           if (_iReplyCode != 220)
           {
               DisConnect();
                throw new IOException(_strReply.Substring(4));
            }
            SendCommand("USER " + _strRemoteUser);
            if (!(_iReplyCode == 331 || _iReplyCode == 230))
            {
                CloseSocketConnect();
                throw new IOException(_strReply.Substring(4));
            }
            if (_iReplyCode != 230)
            {
                SendCommand("PASS " + _strRemotePass);
                if (!(_iReplyCode == 230 || _iReplyCode == 202))
                {
                    CloseSocketConnect();
                    throw new IOException(_strReply.Substring(4));
                }
            }
            _bConnected = true;
            ChDir(_strRemotePath);
        }

        /// <summary>
        /// 关闭连接
        /// </summary>
        public void DisConnect()
        {
            if (_socketControl != null)
            {
                SendCommand("QUIT");
            }
            CloseSocketConnect();
        }
        #endregion

        #region 传输模式
        /// <summary>
        /// 传输模式:二进制类型、ASCII类型
        /// </summary>
        public enum TransferType { Binary, ASCII };

        /// <summary>
        /// 设置传输模式
        /// </summary>
        /// <param name="ttType">传输模式</param>
        public void SetTransferType(TransferType ttType)
        {
            if (ttType == TransferType.Binary)
            {
                SendCommand("TYPE I");//binary类型传输
            }
            else
            {
                SendCommand("TYPE A");//ASCII类型传输
            }
            if (_iReplyCode != 200)
            {
                throw new IOException(_strReply.Substring(4));
            }
            else
            {
                _trType = ttType;
            }
        }

        /// <summary>
        /// 获得传输模式
        /// </summary>
        /// <returns>传输模式</returns>
        public TransferType GetTransferType()
        {
            return _trType;
        }
        #endregion

        #region 文件操作
        /// <summary>
        /// 获得文件列表
        /// </summary>
        /// <param name="strMask">文件名的匹配字符串</param>
        public string[] Dir(string strMask)
        {
            if (!_bConnected)
            {
                Connect();
            }
            Socket socketData = CreateDataSocket();
            SendCommand("NLST " + strMask);
            if (!(_iReplyCode == 150 || _iReplyCode == 125 || _iReplyCode == 226))
            {
                throw new IOException(_strReply.Substring(4));
            }
            _strMsg = "";
            Thread.Sleep(2000);
            while (true)
            {
                int iBytes = socketData.Receive(_buffer, _buffer.Length, 0);
                _strMsg += _ASCII.GetString(_buffer, 0, iBytes);
                if (iBytes < _buffer.Length)
                {
                    break;
                }
            }
            char[] seperator = { '\n' };
            string[] strsFileList = _strMsg.Split(seperator);
            socketData.Close(); //数据socket关闭时也会有返回码
            if (_iReplyCode != 226)
            {
                ReadReply();
                if (_iReplyCode != 226)
                {

                    throw new IOException(_strReply.Substring(4));
                }
            }
            return strsFileList;
        }

        public void newPutByGuid(string strFileName, string strGuid)
        {
            if (!_bConnected)
            {
                Connect();
            }
            string str = strFileName.Substring(0, strFileName.LastIndexOf("\\"));
            string strTypeName = strFileName.Substring(strFileName.LastIndexOf("."));
            strGuid = str + "\\" + strGuid;
            Socket socketData = CreateDataSocket();
            SendCommand("STOR " + Path.GetFileName(strGuid));
            if (!(_iReplyCode == 125 || _iReplyCode == 150))
            {
                throw new IOException(_strReply.Substring(4));
            }
            FileStream input = new FileStream(strGuid, FileMode.Open);
            input.Flush();
            int iBytes = 0;
            while ((iBytes = input.Read(_buffer, 0, _buffer.Length)) > 0)
            {
                socketData.Send(_buffer, iBytes, 0);
            }
            input.Close();
            if (socketData.Connected)
            {
                socketData.Close();
            }
            if (!(_iReplyCode == 226 || _iReplyCode == 250))
            {
                ReadReply();
                if (!(_iReplyCode == 226 || _iReplyCode == 250))
                {
                    throw new IOException(_strReply.Substring(4));
                }
            }
        }

        /// <summary>
        /// 获取文件大小
        /// 当文件在ftp服务器上不存在时,报异常
        /// </summary>
        /// <param name="strFileName">文件名</param>
        /// <returns>文件大小</returns>
        public long GetFileSize(string strFileName)
        {
            if (!_bConnected)
            {
                Connect();
            }
            SendCommand("SIZE " + Path.GetFileName(strFileName));
            long lSize = 0;
            if (_iReplyCode == 213)
            {
                lSize = Int64.Parse(_strReply.Substring(4));
            }
            else
            {
                throw new IOException(_strReply.Substring(4));
            }
            return lSize;
        }


        /// <summary>
        /// 获取文件信息
        /// </summary>
        /// <param name="strFileName">文件名</param>
        /// <returns>文件大小</returns>
        public string GetFileInfo(string strFileName)
        {
            if (!_bConnected)
            {
                Connect();
            }
            Socket socketData = CreateDataSocket();
            SendCommand("LIST " + strFileName);
            string strResult = "";
            if (!(_iReplyCode == 150 || _iReplyCode == 125
                || _iReplyCode == 226 || _iReplyCode == 250))
            {
                throw new IOException(_strReply.Substring(4));
            }
            byte[] b = new byte[512];
            MemoryStream ms = new MemoryStream();

            while (true)
            {
                int iBytes = socketData.Receive(b, b.Length, 0);
                ms.Write(b, 0, iBytes);
                if (iBytes <= 0)
                {

                    break;
                }
            }
            byte[] bt = ms.GetBuffer();
            strResult = System.Text.Encoding.ASCII.GetString(bt);
            ms.Close();
            return strResult;
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="strFileName">待删除文件名</param>
        public void Delete(string strFileName)
        {
            if (!_bConnected)
            {
                Connect();
            }
            SendCommand("DELE " + strFileName);
            if (_iReplyCode != 250)
            {
                throw new IOException(_strReply.Substring(4));
            }
        }

        /// <summary>
        /// 重命名(如果新文件名与已有文件重名,将覆盖已有文件)
        /// </summary>
        /// <param name="strOldFileName">旧文件名</param>
        /// <param name="strNewFileName">新文件名</param>
        public void Rename(string strOldFileName, string strNewFileName)
        {
            if (!_bConnected)
            {
                Connect();
            }
            SendCommand("RNFR " + strOldFileName);
            if (_iReplyCode != 350)
            {
                throw new IOException(_strReply.Substring(4));
            }
            //  如果新文件名与原有文件重名,将覆盖原有文件
            SendCommand("RNTO " + strNewFileName);
            if (_iReplyCode != 250)
            {
                throw new IOException(_strReply.Substring(4));
            }
        }
        #endregion

        #region 上传和下载
        /// <summary>
        /// 下载一批文件
        /// </summary>
        /// <param name="strFileNameMask">文件名的匹配字符串</param>
        /// <param name="strFolder">本地目录(不得以\结束)</param>
        public void Get(string strFileNameMask, string strFolder)
        {
            if (!_bConnected)
            {
                Connect();
            }
            string[] strFiles = Dir(strFileNameMask);
            foreach (string strFile in strFiles)
            {
                if (!strFile.Equals(""))//一般来说strFiles的最后一个元素可能是空字符串
                {
                    Get(strFile, strFolder, strFile);
                }
            }
        }

        /// <summary>
        /// 下载一个文件
        /// </summary>
        /// <param name="strRemoteFileName">要下载的文件名</param>
        /// <param name="strFolder">本地目录(不得以\结束)</param>
        /// <param name="strLocalFileName">保存在本地时的文件名</param>
        public void Get(string strRemoteFileName, string strFolder, string strLocalFileName="")
        {
            Socket socketData = CreateDataSocket();
            try
            {
                if (!_bConnected)
                {
                    Connect();
                }
                SetTransferType(TransferType.Binary);

                strLocalFileName = RegetFileName(strRemoteFileName, strLocalFileName);

                SendCommand("RETR " + strRemoteFileName);
                if (!(_iReplyCode == 150 || _iReplyCode == 125 || _iReplyCode == 226 || _iReplyCode == 250))
                {
                    throw new IOException(_strReply.Substring(4));
                }
                FileStream output = new FileStream(strFolder + "\\" + strLocalFileName, FileMode.Create);
                while (true)
                {
                    int iBytes = socketData.Receive(_buffer, _buffer.Length, 0);
                    output.Write(_buffer, 0, iBytes);
                    if (iBytes <= 0)
                    {
                        break;
                    }
                }
                output.Close();
                if (socketData.Connected)
                {
                    socketData.Close();
                }
                if (!(_iReplyCode == 226 || _iReplyCode == 250))
                {
                    ReadReply();
                    if (!(_iReplyCode == 226 || _iReplyCode == 250))
                    {
                        throw new IOException(_strReply.Substring(4));
                    }
                }
            }
            catch
            {
                socketData.Close();
                socketData = null;
                _socketControl.Close();
                _bConnected = false;
                _socketControl = null;
            }
        }

   /// <summary>
   /// 下载一个文件,支持断点下载
   /// </summary>
   /// <param name="strRemoteFileName"></param>
   /// <param name="strFolder"></param>
   /// <param name="strLocalFileName"></param>
   /// <param name="size"></param>
        public void GetBrokenFile(string strRemoteFileName, string strFolder, string strLocalFileName="")
        {
            if (!_bConnected)
            {
                Connect();
            }
            SetTransferType(TransferType.Binary);

            strLocalFileName = RegetFileName(strRemoteFileName, strLocalFileName);

            long localFileSize = 0;
            var localfileWithFullname = strFolder + "//" + strLocalFileName;
            if (File.Exists(localfileWithFullname))
            {
                FileInfo fInfo = new FileInfo(localfileWithFullname);
                 localFileSize = fInfo.Length;
            }
            else
            {
                throw new Exception("localfile not exists!");
            }

            FileStream output = new
                FileStream(strFolder + "//" + strLocalFileName, FileMode.Append);
            Socket socketData = CreateDataSocket();
            SendCommand("REST " + localFileSize.ToString());
            SendCommand("RETR " + strRemoteFileName);
            if (!(_iReplyCode == 150 || _iReplyCode == 125
            || _iReplyCode == 226 || _iReplyCode == 250))
            {
                throw new IOException(_strReply.Substring(4));
            }

            while (true)
            {
                int iBytes = socketData.Receive(_buffer, _buffer.Length, 0);
                output.Write(_buffer, 0, iBytes);
                if (iBytes <= 0)
                {
                    break;
                }
            }
            output.Close();
            if (socketData.Connected)
            {
                socketData.Close();
            }
            if (!(_iReplyCode == 226 || _iReplyCode == 250))
            {
                ReadReply();
                if (!(_iReplyCode == 226 || _iReplyCode == 250))
                {
                    throw new IOException(_strReply.Substring(4));
                }
            }
        }


        /// <summary>
        /// 下载一个文件 ,智能判断是重新下载或者断点继续下载
        /// 1、当本地文件不存在,或者大小等于0, 重新下载
        /// 2、当本地文件存在, size>0 and size<totalsize,  断点下载
        /// </summary>
        /// <param name="strRemoteFileName"></param>
        /// <param name="strFolder"></param>
        /// <param name="strLocalFileName"></param>
        public void GetFileByRestartOrBroken(string strRemoteFileName, string strFolder, string strLocalFileName = "")
        {
            strLocalFileName = RegetFileName(strRemoteFileName, strLocalFileName);
            long remoteFileSize = 0;
            long localFileSize = 0;
            try
            {
                remoteFileSize = this.GetFileSize(strRemoteFileName);
            }
            catch (Exception ex)
            {
                throw new IOException(string.Format("由于 {0} 导致 GetFileByRestartOrBroken 出现异常", ex.Message));
            }


            var localfileWithFullname = strFolder + "//" + strLocalFileName;
            if (File.Exists(localfileWithFullname))
            {
                FileInfo fInfo = new FileInfo(localfileWithFullname);
                localFileSize = fInfo.Length;
            }
            else
            {
                localFileSize = 0;
            }

            if (localFileSize==0)
            {
                this.Get(strRemoteFileName, strFolder, strLocalFileName);
            }
            else
            {
              this.GetBrokenFile(strRemoteFileName, strFolder,strLocalFileName);
            }
        }



        /// <summary>
        /// 下载一个文件
        /// </summary>
        /// <param name="strRemoteFileName">要下载的文件名</param>
        /// <param name="strFolder">本地目录(不得以\结束)</param>
        /// <param name="strLocalFileName">保存在本地时的文件名</param>
        public void GetNoBinary(string strRemoteFileName, string strFolder, string strLocalFileName="")
        {
            if (!_bConnected)
            {
                Connect();
            }

            strLocalFileName = RegetFileName(strRemoteFileName, strLocalFileName);

            Socket socketData = CreateDataSocket();
            SendCommand("RETR " + strRemoteFileName);
            if (!(_iReplyCode == 150 || _iReplyCode == 125 || _iReplyCode == 226 || _iReplyCode == 250))
            {
                throw new IOException(_strReply.Substring(4));
            }
            FileStream output = new FileStream(strFolder + "\\" + strLocalFileName, FileMode.Create);
            while (true)
            {
                int iBytes = socketData.Receive(_buffer, _buffer.Length, 0);
                output.Write(_buffer, 0, iBytes);
                if (iBytes <= 0)
                {
                    break;
                }
            }
            output.Close();
            if (socketData.Connected)
            {
                socketData.Close();
            }
            if (!(_iReplyCode == 226 || _iReplyCode == 250))
            {
                ReadReply();
                if (!(_iReplyCode == 226 || _iReplyCode == 250))
                {
                    throw new IOException(_strReply.Substring(4));
                }
            }
        }

        /// <summary>
        /// 上传一批文件
        /// </summary>
        /// <param name="strFolder">本地目录(不得以\结束)</param>
        /// <param name="strFileNameMask">文件名匹配字符(可以包含*和?)</param>
        public void Put(string strFolder, string strFileNameMask)
        {
            string[] strFiles = Directory.GetFiles(strFolder, strFileNameMask);
            foreach (string strFile in strFiles)
            {
                Put(strFile);
            }
        }

        /// <summary>
        /// 上传一个文件
        /// </summary>
        /// <param name="strFileName">本地文件名 fullName</param>
        public void Put(string strFileName)
        {
            if (!_bConnected)
            {
                Connect();
            }
            Socket socketData = CreateDataSocket();
            if (Path.GetExtension(strFileName) == "")
                SendCommand("STOR " + Path.GetFileNameWithoutExtension(strFileName));
            else
                SendCommand("STOR " + Path.GetFileName(strFileName));

            if (!(_iReplyCode == 125 || _iReplyCode == 150))
            {
                throw new IOException(_strReply.Substring(4));
            }

            FileStream input = new FileStream(strFileName, FileMode.Open);
            int iBytes = 0;
            while ((iBytes = input.Read(_buffer, 0, _buffer.Length)) > 0)
            {
                socketData.Send(_buffer, iBytes, 0);
            }
            input.Close();
            if (socketData.Connected)
            {
                socketData.Close();
            }
            if (!(_iReplyCode == 226 || _iReplyCode == 250))
            {
                ReadReply();
                if (!(_iReplyCode == 226 || _iReplyCode == 250))
                {
                    throw new IOException(_strReply.Substring(4));
                }
            }
        }

      /// <summary>
        /// 上传一个文件,支持断点上传
      /// </summary>
      /// <param name="strFileName">localfile with fullName</param>
      /// <param name="remoteFileName">remoteFilename</param>
        public void PutBrokenFile(string strFileName,string remoteFileName="")
        {
            if (!_bConnected)
            {
                Connect();
            }
            remoteFileName = RegetFileName(strFileName, remoteFileName);

            long remotefileSize = 0;
           try
           {
             remotefileSize= this.GetFileSize(remoteFileName);
           }
           catch (Exception ex)
           {
               throw new IOException(string.Format("由于 {0} 导致 PutBrokenFile 出现异常",ex.Message));
           }

           try
           {
               if (!File.Exists(strFileName))
               {
                   throw new IOException(string.Format("由于 {0} 导致 PutBrokenFile 出现异常","待上传的文件不存在"));
               }

               var fInfo = new FileInfo(strFileName);
               var localFilesize = fInfo.Length;
               if (localFilesize < remotefileSize)
               {
                   throw new IOException(string.Format("由于 {0} 导致 PutBrokenFile 出现异常", "本地文件小于服务器文件 ,不能再断点上传"));
               }
           }
           catch (Exception ex)
           {
               throw new IOException(string.Format("由于 {0} 导致 PutBrokenFile 出现异常", ex.Message));
           }
           
            Socket socketData = CreateDataSocket();
            if (Path.GetExtension(strFileName) == "")
                SendCommand("APPE " + Path.GetFileNameWithoutExtension(strFileName));
            else
                SendCommand("APPE " + Path.GetFileName(strFileName));

            if (!(_iReplyCode == 125 || _iReplyCode == 150))
            {
                throw new IOException(_strReply.Substring(4));
            }

            FileStream input = new FileStream(strFileName, FileMode.Open);
            input.Seek(remotefileSize, SeekOrigin.Begin);
            int iBytes = 0;
            while ((iBytes = input.Read(_buffer, 0, _buffer.Length)) > 0)
            {
                socketData.Send(_buffer, iBytes, 0);
            }
            input.Close();
            if (socketData.Connected)
            {
                socketData.Close();
            }
            if (!(_iReplyCode == 226 || _iReplyCode == 250))
            {
                ReadReply();
                if (!(_iReplyCode == 226 || _iReplyCode == 250))
                {
                    throw new IOException(_strReply.Substring(4));
                }
            }
        }


            /// <summary>
        /// 上传一个文件 ,智能判断是重新上传或者断点续传
        /// 1、当ftp服务器文件不存在,或者大小等于0, 重新下载
        /// 2、当ftp服务器文件存在, size>0 and size<totalsize, 断点续传
        /// </summary>
        /// <param name="localFileName">localfile with fullname</param>
        /// <param name="remoteFileName">remote file name </param>
        public void PutFileByRestartOrBroken(string localFileName, string remoteFileName = "")
        {
            remoteFileName = RegetFileName(localFileName, remoteFileName);
            long remoteFileSize = 0;
            long localFileSize = 0;
            try
            {
                remoteFileSize = this.GetFileSize(remoteFileName);
            }
            catch (Exception ex)
            {
                remoteFileSize = 0;
            }


            if (File.Exists(localFileName))
            {
                FileInfo fInfo = new FileInfo(localFileName);
                localFileSize = fInfo.Length;
            }
            else
            {
                localFileSize = 0;
            }

            if (remoteFileSize == 0)
            {
                this.Put(localFileName);
            }
            else
            {
                this.PutBrokenFile(localFileName, remoteFileName);
            }
        }

        private static string RegetFileName(string strFileName, string strNullOrNo)
        {
            string rtnString = "";
            if (string.IsNullOrEmpty(strNullOrNo))
            {
                if (Path.GetExtension(strFileName) == "")
                {
                    rtnString = Path.GetFileNameWithoutExtension(strFileName);
                }
                else
                {
                    rtnString = Path.GetFileName(strFileName);
                }
            }
            else
            {
                rtnString = strNullOrNo;
            }
            return rtnString;
        }


        /// <summary>
        /// 上传一个文件
        /// </summary>
        /// <param name="strFileName">本地文件名</param>
        public void PutByGuid(string strFileName, string strGuid)
        {
            if (!_bConnected)
            {
                Connect();
            }
            string str = strFileName.Substring(0, strFileName.LastIndexOf("\\"));
            string strTypeName = strFileName.Substring(strFileName.LastIndexOf("."));
            strGuid = str + "\\" + strGuid;
            System.IO.File.Copy(strFileName, strGuid);
            System.IO.File.SetAttributes(strGuid, System.IO.FileAttributes.Normal);
            Socket socketData = CreateDataSocket();
            SendCommand("STOR " + Path.GetFileName(strGuid));
            if (!(_iReplyCode == 125 || _iReplyCode == 150))
            {
                throw new IOException(_strReply.Substring(4));
            }
            FileStream input = new FileStream(strGuid, FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read);
            int iBytes = 0;
            while ((iBytes = input.Read(_buffer, 0, _buffer.Length)) > 0)
            {
                socketData.Send(_buffer, iBytes, 0);
            }
            input.Close();
            File.Delete(strGuid);
            if (socketData.Connected)
            {
                socketData.Close();
            }
            if (!(_iReplyCode == 226 || _iReplyCode == 250))
            {
                ReadReply();
                if (!(_iReplyCode == 226 || _iReplyCode == 250))
                {
                    throw new IOException(_strReply.Substring(4));
                }
            }
        }
        #endregion

        #region 目录操作
        /// <summary>
        /// 创建目录
        /// </summary>
        /// <param name="strDirName">目录名</param>
        public void MkDir(string strDirName)
        {
            if (!_bConnected)
            {
                Connect();
            }
            SendCommand("MKD " + strDirName);
            if (_iReplyCode != 257)
            {
                throw new IOException(_strReply.Substring(4));
            }
        }

        /// <summary>
        /// 删除目录
        /// </summary>
        /// <param name="strDirName">目录名</param>
        public void RmDir(string strDirName)
        {
            if (!_bConnected)
            {
                Connect();
            }
            SendCommand("RMD " + strDirName);
            if (_iReplyCode != 250)
            {
                throw new IOException(_strReply.Substring(4));
            }
        }

        /// <summary>
        /// 改变目录
        /// </summary>
        /// <param name="strDirName">新的工作目录名</param>
        public void ChDir(string strDirName)
        {
            if (strDirName.Equals(".") || strDirName.Equals(""))
            {
                return;
            }
            if (!_bConnected)
            {
                Connect();
            }
            SendCommand("CWD " + strDirName);
            if (_iReplyCode != 250)
            {
                throw new IOException(_strReply.Substring(4));
            }
            this._strRemotePath = strDirName;
        }
        #endregion

        #region 内部函数
        /// <summary>
        /// 将一行应答字符串记录在strReply和strMsg,应答码记录在iReplyCode
        /// </summary>
        private void ReadReply()
        {
            _strMsg = "";
            _strReply = ReadLine();
            _iReplyCode = Int32.Parse(_strReply.Substring(0, 3));
        }

        /// <summary>
        /// 建立进行数据连接的socket
        /// </summary>
        /// <returns>数据连接socket</returns>
        private Socket CreateDataSocket()
        {
            SendCommand("PASV");
            if (_iReplyCode != 227)
            {
                throw new IOException(_strReply.Substring(4));
            }
            int index1 = _strReply.IndexOf('(');
            int index2 = _strReply.IndexOf(')');
            string ipData = _strReply.Substring(index1 + 1, index2 - index1 - 1);
            int[] parts = new int[6];
            int len = ipData.Length;
            int partCount = 0;
            string buf = "";
            for (int i = 0; i < len && partCount <= 6; i++)
            {
                char ch = Char.Parse(ipData.Substring(i, 1));
                if (Char.IsDigit(ch))
                    buf += ch;
                else if (ch != ',')
                {
                    throw new IOException("Malformed PASV strReply: " + _strReply);
                }
                if (ch == ',' || i + 1 == len)
                {
                    try
                    {
                        parts[partCount++] = Int32.Parse(buf);
                        buf = "";
                    }
                    catch (Exception)
                    {
                        throw new IOException("Malformed PASV strReply: " + _strReply);
                    }
                }
            }
            string ipAddress = parts[0] + "." + parts[1] + "." + parts[2] + "." + parts[3];
            int port = (parts[4] << 8) + parts[5];
            Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint ep = new IPEndPoint(IPAddress.Parse(ipAddress), port);
            try
            {
                s.Connect(ep);
            }
            catch (Exception)
            {
                throw new IOException("无法连接ftp服务器");
            }
            return s;
        }

        /// <summary>
        /// 关闭socket连接(用于登录以前)
        /// </summary>
        private void CloseSocketConnect()
        {
            lock (_obj)
            {
                if (_socketControl != null)
                {
                    _socketControl.Close();
                    _socketControl = null;
                }
                _bConnected = false;
            }
        }

        /// <summary>
        /// 读取Socket返回的所有字符串
        /// </summary>
        /// <returns>包含应答码的字符串行</returns>
        private string ReadLine()
        {
            lock (_obj)
            {
                while (true)
                {
                    int iBytes = _socketControl.Receive(_buffer, _buffer.Length, 0);
                    _strMsg += _ASCII.GetString(_buffer, 0, iBytes);
                    if (iBytes < _buffer.Length)
                    {
                        break;
                    }
                }
            }
            char[] seperator = { '\n' };
            string[] mess = _strMsg.Split(seperator);
            if (_strMsg.Length > 2)
            {
                _strMsg = mess[mess.Length - 2];
            }
            else
            {
                _strMsg = mess[0];
            }
            if (!_strMsg.Substring(3, 1).Equals(" ")) //返回字符串正确的是以应答码(如220开头,后面接一空格,再接问候字符串)
            {
                return ReadLine();
            }
            return _strMsg;
        }

        /// <summary>
        /// 发送命令并获取应答码和最后一行应答字符串
        /// </summary>
        /// <param name="strCommand">命令</param>
        public void SendCommand(String strCommand)
        {
            lock (_obj)
            {
              //  Byte[] cmdBytes =  Encoding.ASCII.GetBytes((strCommand + "\r\n").ToCharArray());
                Byte[] cmdBytes = _ASCII.GetBytes((strCommand + "\r\n").ToCharArray());
                _socketControl.Send(cmdBytes, cmdBytes.Length, 0);
                Thread.Sleep(500);   
                ReadReply();
            }
        }
        #endregion

        public void Dispose()
        {
           this.DisConnect();
        }
    }

  2、 测试代码

 class Program
    {
        static void Main(string[] args)
        {
           // FtpFirstTest();
           // GetBrokenFileTest();
           // FileSizeTest();
           // FtpPutBrokenFile();

           // SmartGet();

            SmartPutFile();

            Console.WriteLine("ftp finished");
            Console.ReadKey();
        }

        private static void FtpFirstTest()
        {
            var ftpServer = ConfigurationSettings.AppSettings["ftpServer"];
            var ftpPort = ConfigurationSettings.AppSettings["ftpPort"];
            var userName = ConfigurationSettings.AppSettings["userName"];
            var pwd = ConfigurationSettings.AppSettings["pwd"];

            try
            {
                using (var ftp = new FTPClient(ftpServer, "/", userName, pwd, int.Parse(ftpPort)))
                {
                    if (!ftp.Connected)
                    {
                        ftp.Connect();
                    }
                  //  ftp.Put("D:\\programShareFile\\[阳光电影www.ygdy8.com].44号孩子.BD.720p.中英双字幕.rmvb");
                    Console.WriteLine("ftp operation");
                    ftp.GetNoBinary("[阳光电影www.ygdy8.com].44号孩子.BD.720p.中英双字幕.rmvb", "D:\\programShareFile", "[阳光电影www.ygdy8.com].44号孩子.BD.720p.中英双字幕.rmvb");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("ftp exception   msg:" + ex.Message);
            }
        }

     
        /// <summary>
        ///    断点下载测试
        /// </summary>
        static void GetBrokenFileTest()
        {
            var ftpServer = ConfigurationSettings.AppSettings["ftpServer"];
            var ftpPort = ConfigurationSettings.AppSettings["ftpPort"];
            var userName = ConfigurationSettings.AppSettings["userName"];
            var pwd = ConfigurationSettings.AppSettings["pwd"];

            try
            {
                using (var ftp = new FTPClient(ftpServer, "/", userName, pwd, int.Parse(ftpPort)))
                {
                    if (!ftp.Connected)
                    {
                        ftp.Connect();
                    }
                    //Console.WriteLine("ftp operation ing"); 
                    //ftp.Put("D:\\programShareFile\\[阳光电影www.ygdy8.com].44号孩子.BD.720p.中英双字幕.rmvb");
                    //Console.WriteLine("ftp operation");
                    var localfile = "D:\\programShareFile\\apicloudFtp.zip";
                    if (File.Exists(localfile))
                    {
                        FileInfo fInfo = new FileInfo(localfile);
                        var size = fInfo.Length;
                        Console.WriteLine("file now size=" + size.ToString());
                        ftp.GetBrokenFile("apicloudFtp.zip", "D:\\programShareFile", "apicloudFtp.zip");
                    }
                    else
                    {
                        Console.WriteLine("file not exists");
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("ftp exception   msg:" + ex.Message);
            }

        }

        /// <summary>
        /// 获取ftp服务器文件大小 测试。  存在的文件  ,不存在的文件
        /// </summary>
        static void FileSizeTest()
        {
            var ftpServer = ConfigurationSettings.AppSettings["ftpServer"];
            var ftpPort = ConfigurationSettings.AppSettings["ftpPort"];
            var userName = ConfigurationSettings.AppSettings["userName"];
            var pwd = ConfigurationSettings.AppSettings["pwd"];

            try
            {
                using (var ftp = new FTPClient(ftpServer, "/", userName, pwd, int.Parse(ftpPort)))
                {
                    if (!ftp.Connected)
                    {
                        ftp.Connect();
                    }
                    Console.WriteLine("ftp operation");
                    var localfile = "D:\\programShareFile\\[阳光电影www.ygdy8.com].44号孩子.BD.720p.中英双字幕.rmvb";

                    var remoteFile = "[阳光电影www.ygdy8.com].44号孩子.BD.720p.中英双字幕.rmvb";
                    var remoteFile2 = "apicloudFtp22.zip";
          
                    try
                    {
                        var size = ftp.GetFileSize(remoteFile2);
                        Console.WriteLine(string.Format("file size={0}",size));
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("ftp getfilesize exception ");
                    }

                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("ftp exception   msg:" + ex.Message);
            }
        }

        /// <summary>
        /// 测试 ftp 断点上传
        /// </summary>
        static void FtpPutBrokenFile()
        {
            var ftpServer = ConfigurationSettings.AppSettings["ftpServer"];
            var ftpPort = ConfigurationSettings.AppSettings["ftpPort"];
            var userName = ConfigurationSettings.AppSettings["userName"];
            var pwd = ConfigurationSettings.AppSettings["pwd"];

            try
            {
                using (var ftp = new FTPClient(ftpServer, "/", userName, pwd, int.Parse(ftpPort)))
                {
                    if (!ftp.Connected)
                    {
                        ftp.Connect();
                    }
                    Console.WriteLine("ftp operation");
                    var localfile = "D:\\programShareFile\\[阳光电影www.ygdy8.com].44号孩子.BD.720p.中英双字幕.rmvb";

                    var remoteFile = "apicloudFtp.zip";

                    try
                    {
                        ftp.PutBrokenFile(localfile, "");
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("ftp.PutBrokenFile exception ");
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("ftp exception   msg:" + ex.Message);
            }
        }

        /// <summary>
        /// 智能下载测试
        /// </summary>
        static void SmartGet()
        {
            var ftpServer = ConfigurationSettings.AppSettings["ftpServer"];
            var ftpPort = ConfigurationSettings.AppSettings["ftpPort"];
            var userName = ConfigurationSettings.AppSettings["userName"];
            var pwd = ConfigurationSettings.AppSettings["pwd"];

            try
            {
                using (var ftp = new FTPClient(ftpServer, "/", userName, pwd, int.Parse(ftpPort)))
                {
                    if (!ftp.Connected)
                    {
                        ftp.Connect();
                    }
                    Console.WriteLine("ftp operation");
                   // var localfile = "D:\\programShareFile\\apicloudFtp.zip";

                        ftp.GetFileByRestartOrBroken("[阳光电影www.ygdy8.com].44号孩子.BD.720p.中英双字幕.rmvb", "D:\\programShareFile", "[阳光电影www.ygdy8.com].44号孩子.BD.720p.中英双字幕.rmvb");

                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("ftp exception   msg:" + ex.Message);
            }
        }


        static void SmartPutFile()
        {
            var ftpServer = ConfigurationSettings.AppSettings["ftpServer"];
            var ftpPort = ConfigurationSettings.AppSettings["ftpPort"];
            var userName = ConfigurationSettings.AppSettings["userName"];
            var pwd = ConfigurationSettings.AppSettings["pwd"];

            try
            {
                using (var ftp = new FTPClient(ftpServer, "/", userName, pwd, int.Parse(ftpPort)))
                {
                    if (!ftp.Connected)
                    {
                        ftp.Connect();
                    }
                    Console.WriteLine("ftp operation");
                    var localfile = "D:\\programShareFile\\[阳光电影www.ygdy8.com].44号孩子.BD.720p.中英双字幕.rmvb";

                    try
                    {
                        ftp.PutFileByRestartOrBroken(localfile);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("ftp.PutBrokenFile exception ");
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("ftp exception   msg:" + ex.Message);
            }
        }
    }

  3 config配置

 

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
  <appSettings>
    <add key="ftpServer" value="127.0.0.1"/>
    <add key="ftpPort" value="21"/>
    <add key="userName" value="hyt"/>
    <add key ="pwd" value="hyt"/>
  </appSettings>
</configuration>

  4  使用到 filezilla server   ftp服务器。测试正常工作

      5  为了更加方便的理解ftp原理,附上ftp命令和响应值文档 

FTP命令字和响应码解释

FTP命令

 
命令     描述 
ABOR    中断数据连接程序
ACCT <account>    系统特权帐号
ALLO <bytes>     为服务器上的文件存储器分配字节
APPE <filename>    添加文件到服务器同名文件
CDUP <dir path>    改变服务器上的父目录
CWD <dir path>    改变服务器上的工作目录
DELE <filename>    删除服务器上的指定文件
HELP <command>    返回指定命令信息
LIS2T <name>    如果是文件名列出文件信息,如果是目录则列出文件列表
MODE <mode>    传输模式(S=流模式,B=块模式,C=压缩模式)
MKD <directory>    在服务器上建立指定目录
NLST <directory>    列出指定目录内容
NOOP    无动作,除了来自服务器上的承认
PASS <password>    系统登录密码
PASV    请求服务器等待数据连接
PORT <address>    IP 地址和两字节的端口 ID
PWD    显示当前工作目录
QUIT    从 FTP 服务器上退出登录
REIN    重新初始化登录状态连接
REST <offset>    由特定偏移量重启文件传递
RETR <filename>    从服务器上找回(复制)文件
RMD <directory>    在服务器上删除指定目录
RNFR <old path>    对旧路径重命名
RNTO <new path>    对新路径重命名
SITE <params>    由服务器提供的站点特殊参数
SMNT <pathname>    挂载指定文件结构
STAT <directory>    在当前程序或目录上返回信息
STOR <filename>    储存(复制)文件到服务器上
STOU <filename>    储存文件到服务器名称上
STRU <type>    数据结构(F=文件,R=记录,P=页面)
SYST    返回服务器使用的操作系统
TYPE <data type>    数据类型(A=ASCII,E=EBCDIC,I=binary)
USER <username>>    系统登录的用户名
 
FTP响应码

 
响应代码     解释说明 
110    新文件指示器上的重启标记
120    服务器准备就绪的时间(分钟数)
125    打开数据连接,开始传输
150    打开连接
200    成功
202    命令没有执行
211    系统状态回复
212    目录状态回复
213    文件状态回复
214    帮助信息回复
215    系统类型回复
220    服务就绪
221    退出网络
225    打开数据连接
226    结束数据连接
227    进入被动模式(IP 地址、ID 端口)
230    登录因特网
250    文件行为完成
257    路径名建立
331    要求密码
332    要求帐号
350    文件行为暂停
421    服务关闭
425    无法打开数据连接
426    结束连接
450    文件不可用
451    遇到本地错误
452    磁盘空间不足
500    无效命令
501    错误参数
502    命令没有执行
503    错误指令序列
504    无效命令参数
530    未登录网络
532    存储文件需要帐号
550    文件不可用
551    不知道的页类型
552    超过存储分配
553    文件名不允许

  

 

posted @ 2016-01-07 16:38  swan.huang  阅读(1572)  评论(0编辑  收藏  举报