先奉献一个测试地址,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(); } } }
目录详细信息类
/// <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
辅助函数
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 + "-----------"; } }