C# 实现 微软WebRequestMethods.Ftp类中的FTP操作功能

先奉献一个测试地址,ftp内的文件请勿删除,谢谢

FtpEntity fe = new FtpEntity("wjshan0808.3vhost.net", "wjshan0808", "1234567890");

由于代码量较多,只抽出一部分,详细代码请移步  ftp://wjshan0808.3vhost.net/FtpEntity/或 随笔后面有源码下载地址

部分字段
        #region fields
        private const string PATTERN = @"^([dlb-])([rwx-]{9})s+(d{1,})s+(w+)s+(.+?)s+(d{1,})s+(.+?)s+(d{1,2})s+(d{2}:?d{2})s+(.+)$";
        private const int DYNAMICINCREASEVALUE = 1024 * 512;//512KB
        private const int DYNAMICIMCEPTVALUE = 1024 * 64;//64KB;
        private static ReaderWriterLock _lok = new ReaderWriterLock();
        private int _dynamicBufferSize = 0;
        private bool _isDownloadCheck = true;
        private bool _isUploadCheck = false;
        private Dictionary<Uri, long> _dicFileSize = null;
        private int _sendBufferSize = 1024 * 128;//128KB
        #endregion
        #region props
        /// <summary>
        /// 当文件数据上传完成时发生
        /// </summary>
        public event UploadCompletedEventHandler UploadCompleted;
        /// <summary>
        /// 获取或设置上传数据的缓冲区大小
        /// </summary>
        public int SendBufferSize
        {
            get { return _sendBufferSize; }
            set
            {
                if (value < 1)
                    value = 1024 * 128;
                _lok.AcquireWriterLock(1000);
                try
                {
                    _sendBufferSize = value;
                }
                finally
                {
                    _lok.ReleaseWriterLock();
                }
            }
        }
        /// <summary>
        /// 获取请求FTP服务器的协议地址
        /// </summary>
        public string Address
        {
            get { return string.Format("ftp://{0}:{1}", _address, Port); }
        }
        /// <summary>
        /// 获取或设置相对FTP根目录的绝对路径,默认为Ftp根目录
        /// </summary>
        public string AbsolutePath
        {
            get { return _absolutePath; }
            set
            {
                IsNull(ref value);
                while (value.StartsWith("/"))
                {
                    value = value.TrimStart('/');
                }
                if (value.IndexOfAny(Path.GetInvalidPathChars()) >= 0)
                    throw new ArgumentException("RelativeUrl:Invalid Value");
                _absolutePath = value;
            }
        }
        /// <summary>
        /// 获取请求FTP服务器的解析地址
        /// </summary>
        public string ResolveUrl
        {
            get { return Path.Combine(Address, AbsolutePath).Replace(@"", "/"); }
        }
        #endregion

1.获取详细列表

        /// <summary>
        /// 获取 AbsolutePath (属性值)下的文件(夹)的详细列表
        /// </summary>
        /// <param name="total">总用量</param>
        /// <param name="absolutePath">目标地址</param>
        /// <returns>文件(夹)详细信息</returns>
        public FtpDirectoryDetails[] ListDirectoryDetails(out int total, string absolutePath = null)
        {
            if (absolutePath != null && absolutePath != string.Empty)
                AbsolutePath = absolutePath;
            using (FtpWebResponse response = SyncInternalCommon(WebRequestMethods.Ftp.ListDirectoryDetails))
            {
                total = 0;
                IList<FtpDirectoryDetails> fddes = new List<FtpDirectoryDetails>(16);
                StreamReader reader = null;
                try
                {
                    if (response.StatusCode == FtpStatusCode.OpeningData)
                    {
                        reader = new StreamReader(response.GetResponseStream(), Encoding.Default, true);
                    }
                    if (reader == null) throw new ArgumentNullException("reader");
                    while (!reader.EndOfStream)
                    {
                        string line = reader.ReadLine();
                        MatchCollection mc = Regex.Matches(line, PATTERN, RegexOptions.CultureInvariant);
                        if (mc.Count == 1)
                        {
                            object[] tmp = new object[11];
                            mc[0].Groups.CopyTo(tmp, 0);
                            fddes.Add(new FtpDirectoryDetails(tmp));
                        }
                        else //total
                        {
                            total = int.Parse(Regex.Match(line, @"d{1,}", RegexOptions.CultureInvariant).Value);
                        }
                    }
                    return fddes.ToArray();
                }
                catch (Exception ex)
                {
                    Log(ex);
                    throw ex;
                }
                finally
                {
                    if (reader != null)
                        reader.Close();
                }
            }
        }
View Code

目录详细信息类

    /// <summary>
    /// 目录文件信息
    /// </summary>
    public struct FtpDirectoryDetails
    {
        public FtpDirectoryType Type { get; set; }
        public FtpDirectoryAccess[] Access { get; set; }
        public short Count { get; set; }
        public string User { get; set; }
        public string Group { get; set; }
        public long Size { get; set; }
        public DateTime LastModified { get; set; }
        //public string Year { get; set; }
        public string Name { get; set; }


        public FtpDirectoryDetails(object[] details)
        {
            Type = FtpDirectoryType.Unknow;
            Access = new FtpDirectoryAccess[3] { FtpDirectoryAccess.None, FtpDirectoryAccess.None, FtpDirectoryAccess.None };

            Count = short.Parse(details[3].ToString());
            User = details[4].ToString();
            Group = details[5].ToString();

            Size = long.Parse(details[6].ToString());

            LastModified = DateTime.MinValue;

            Name = details[10].ToString();
            //
            SetType(details[1].ToString());
            SetAccess(details[2].ToString());
            SetLastModified(details[7].ToString(), details[8].ToString(), details[9].ToString());
        }

        private void SetLastModified(string month, string day, string time0year)
        {
            StringBuilder sb = new StringBuilder(16);
            bool contains = time0year.Contains(":");
            sb.Append(contains ? DateTime.Now.Year.ToString() : time0year);
            sb.Append(" ");
            sb.Append(string.Format("{0:00}", SetMonth(month)));
            sb.Append(" ");
            sb.Append(string.Format("{0:00}", day));
            sb.Append(" ");
            sb.Append(contains ? time0year : "00:00");
            sb.Append(":00");
            LastModified = DateTime.Parse(sb.ToString());
        }

        /// <summary>
        /// 1.英文
        /// 2.阿拉伯数字
        /// 3.两位阿拉伯数字
        /// 4.(2,3)+中文
        /// </summary>
        /// <param name="month"></param>
        /// <returns></returns>
        private object SetMonth(string month)
        {
            if (month[month.Length - 1] <= 57)//最后一位是数字 
                return month;

            if (month[0] <= 57)//第一位是数字
                return month.Substring(0, month.Length - 1);

            if ("January".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//Jan
                return 1;
            else if ("February".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//Feb
                return 2;
            else if ("March".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//Mar
                return 3;
            else if ("April".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//Apr
                return 4;
            else if ("May".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//May
                return 5;
            else if ("June".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//Jun
                return 6;
            else if ("July".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//Jul
                return 7;
            else if ("August".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//Aug
                return 8;
            else if ("September".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//Sep
                return 9;
            else if ("October".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//Oct
                return 10;
            else if ("November".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//Nov
                return 11;
            else
                //("December".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//Dec
                return 12;
        }

        private void SetAccess(string access)
        {
            for (int i = 0; i < access.Length; i += 3)
            {
                FtpDirectoryAccess acc = FtpDirectoryAccess.None;
                for (int j = i; j < (i + 3); j++)
                {
                    switch (access[j])
                    {
                        case 'r':
                            acc |= FtpDirectoryAccess.Read;
                            break;
                        case 'w':
                            acc |= FtpDirectoryAccess.Write;
                            break;
                        case 'x':
                            acc |= FtpDirectoryAccess.Execute;
                            break;
                        default:// '-':
                            acc |= FtpDirectoryAccess.None;
                            break;
                    }
                }
                Access[i / 3] = acc;
            }
        }
        private void SetType(string type)
        {
            switch (type)
            {
                case "d":
                    Type = FtpDirectoryType.Folder;
                    break;
                case "-":
                    Type = FtpDirectoryType.File;
                    break;
                case "l":
                    Type = FtpDirectoryType.Link;
                    break;
                case "b":
                    Type = FtpDirectoryType.Block;
                    break;
                default:
                    Type = FtpDirectoryType.Unknow;
                    break;
            }
        }
    }

2.上传

        #region UploadCommon
        protected void SyncUploadCommon(string file, bool withUnique = false, long offset = 0)
        {
            CheckUrl(file, withUnique);
            FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read);
            if (offset > 0)
                fs.Seek(offset, SeekOrigin.Begin);
            FtpWebRequest request = WebRequest.Create(ResolveUrl) as FtpWebRequest;
            request.Credentials = Credential;
            request.UsePassive = false;
            request.ContentLength = fs.Length;
            if (withUnique && offset == 0)
                request.Method = WebRequestMethods.Ftp.UploadFileWithUniqueName;
            else
                request.Method = offset > 0 ? WebRequestMethods.Ftp.AppendFile : WebRequestMethods.Ftp.UploadFile;
            string path = request.RequestUri.AbsolutePath;
            Stream stream = null;
            BinaryReader reader = null;
            FtpTransmissionStatus status = FtpTransmissionStatus.Ok;
            try
            {
                stream = request.GetRequestStream();
                if (stream == null)
                    throw new ArgumentNullException("stream");
                reader = new BinaryReader(fs, Encoding.Default);
                if (reader == null)
                    throw new ArgumentNullException("reader");
                while (reader.PeekChar() != -1)
                {
                    byte[] bt = reader.ReadBytes(_sendBufferSize);
                    stream.Write(bt, 0, bt.Length);
                    stream.Flush();
                }
                //GetResponse after Close

            }
            catch (Exception ex)
            {
                status = FtpTransmissionStatus.Error;
                Log(ex);
                //throw ex;
            }
            finally
            {
                if (reader != null)
                    reader.Close();
                if (stream != null)
                    stream.Close();

                if (UploadCompleted != null)
                {
                    Thread.Sleep(124);
                    UploadCompleted(new object(),
                        new UploadCompletedEventArgs()
                        {
                            Length = (!withUnique && IsUploadCheck) ? GetFileSize(path) : -1,//异步时文件路径会改变
                            Path = path,
                            FileName = (!withUnique) ? Path.GetFileName(path) : string.Empty,
                            UploadStatus = status
                        });
                }
            }
        }
        protected void AsyncUploadCommon(string file, long offset = 0, bool withUnique = false)
        {
            CheckUrl(file, withUnique);
            FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read);
            if (offset > 0)
                fs.Seek(offset, SeekOrigin.Begin);
            FtpWebRequest request = WebRequest.Create(ResolveUrl) as FtpWebRequest;
            request.Credentials = Credential;
            request.UsePassive = false;
            request.ContentLength = fs.Length;
            if (withUnique && offset == 0)
                request.Method = WebRequestMethods.Ftp.UploadFileWithUniqueName;
            else
                request.Method = offset > 0 ? WebRequestMethods.Ftp.AppendFile : WebRequestMethods.Ftp.UploadFile;

            FtpState state = new FtpState() { Request = request, FileStream = fs, Path = request.RequestUri.AbsolutePath, Unique = withUnique };
            try
            {
                IAsyncResult iar = request.BeginGetRequestStream(new AsyncCallback(UploadCallBack), state);
            }
            catch (Exception ex)
            {
                Log(ex);
                state.Dispose();
                //throw ex;
            }
        }
        protected void UploadCallBack(IAsyncResult ar)
        {
            FtpState state = ar.AsyncState as FtpState;
            if (state == null) throw new ArgumentNullException("state");
            if (state.Request == null) throw new ArgumentNullException("state.Request");
            if (state.FileStream == null) throw new ArgumentNullException("state.FileStream");
            FtpTransmissionStatus status = FtpTransmissionStatus.Ok;
            try
            {
                if (ar.IsCompleted)
                {
                    Stream stream = state.Request.EndGetRequestStream(ar);
                    if (stream == null)
                        throw new ArgumentNullException("stream");
                    state.Stream = stream;
                }
                while (IsReadToEnd)
                {
                    byte[] bt = new byte[SendBufferSize];
                    int length = state.FileStream.Read(bt, 0, bt.Length);
                    if (length == 0) break;
                    IAsyncResult iar = state.Stream.BeginWrite(bt, 0, length, null, null);
                    state.Stream.EndWrite(iar);
                    state.Stream.Flush();
                }
                //GetResponse after Close

            }
            catch (Exception ex)
            {
                status = FtpTransmissionStatus.Error;
                Log(ex);
                //throw ex;
            }
            finally
            {
                string path = state.Path;
                bool withUnique = state.Unique;
                state.Dispose();

                if (UploadCompleted != null)
                {
                    Thread.Sleep(124);
                    UploadCompleted(new object(),
                        new UploadCompletedEventArgs()
                        {
                            Length = (!withUnique && IsUploadCheck) ? GetFileSize(path) : -1,//异步时文件路径会改变
                            Path = path,
                            FileName = (!withUnique) ? Path.GetFileName(path) : string.Empty,
                            UploadStatus = status
                        });
                }
            }
        }
        #endregion
View Code

辅助函数

        private int DynamicBufferSize(int length)
        {
            if (length == 0)
                length += DYNAMICIMCEPTVALUE;
            if (length == _dynamicBufferSize)
                length += DYNAMICINCREASEVALUE;
            length += -_dynamicBufferSize;
            if ((length + _dynamicBufferSize) <= 0)
                length += DYNAMICIMCEPTVALUE;
            return Interlocked.Add(ref _dynamicBufferSize, length);
        }
        private void CheckPath(string path)
        {
            if (path == null)
                throw new ArgumentNullException(path);
            if (path.IndexOfAny(Path.GetInvalidPathChars()) >= 0)
                throw new ArgumentException("Invalid Path");
            if (!File.Exists(path))
                throw new FileNotFoundException();
        }
        private string CheckName(string value)
        {
            if (value == null || value == string.Empty)
                throw new ArgumentNullException(value);
            if (value.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
                throw new WarningException(value + "Invalid FileName");
            return value;
        }
        private void CheckUrl(string file, bool withUnique)
        {
            string name = Path.GetFileName(file);
            string uploadname = Path.GetFileName(AbsolutePath);
            if (uploadname == string.Empty)
            {
                AbsolutePath = AbsolutePath.TrimEnd(new char[] { '/' }) + "/" + name;
            }
        }
        private void IsNull(ref string value)
        {
            if (value != null) return;
            value = string.Empty;
        }

测试代码

        private void btnTest_Click(object sender, EventArgs e)
        {
            fe.UploadCompleted += new UploadCompletedEventHandler(Fe_UploadCompleted);
            try
            {
                fe.AbsolutePath = "FtpEntity";
                Files(@"C:UsersAdministratorDesktopFtpEntityFtpEntity");
            }
            catch (Exception ex)
            {
            }
        }
        public void Files(string dir)
        {
            DirectoryInfo di = new DirectoryInfo(dir);
            foreach (DirectoryInfo item in di.GetDirectories())
            {
                string tmp1 = fe.AbsolutePath;
                fe.AbsolutePath += "/" + item.Name;
                fe.MakeDirectory();
                Files(item.FullName);
                fe.AbsolutePath = tmp1;
            }
            foreach (FileInfo fi in di.GetFiles())
            {
                string tmp2 = fe.AbsolutePath;
                fe.AbsolutePath += "/" + fi.Name;
                fe.AsyncUploadFile(fi.FullName);
                fe.AbsolutePath = tmp2;
            }
        }
        private void Fe_UploadCompleted(object sender, UploadCompletedEventArgs e)
        {
            if (rtxtLog.InvokeRequired)
            {
                rtxtLog.Invoke(new UploadCompletedEventHandler(Fe_UploadCompleted), new object[] { sender, e });
            }
            else
            {
                rtxtLog.Text += Environment.NewLine + "-----------";
                rtxtLog.Text += e.Length + Environment.NewLine
                    + e.FileName + Environment.NewLine
                    + e.FileSize + Environment.NewLine
                    + e.Path + Environment.NewLine
                    + e.UploadStatus;
                rtxtLog.Text += Environment.NewLine + "-----------";
            }
        }

源文件地址 http://pan.baidu.com/s/1o6rLR2y

原文地址:https://www.cnblogs.com/wjshan0808/p/4945645.html