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

时间:2021-11-13 12:35:20

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

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

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

部分字段
#region fields
private const string PATTERN = @"^([dlb-])([rwx-]{9})\s+(\d{1,})\s+(\w+)\s+(.+?\b)\s+(\d{1,})\s+(.+?)\s+(\d{1,2})\s+(\d{2}:?\d{2})\s+(.+)$";
private const int DYNAMICINCREASEVALUE = * ;//512KB
private const int DYNAMICIMCEPTVALUE = * ;//64KB;
private static ReaderWriterLock _lok = new ReaderWriterLock();
private int _dynamicBufferSize = ;
private bool _isDownloadCheck = true;
private bool _isUploadCheck = false;
private Dictionary<Uri, long> _dicFileSize = null;
private int _sendBufferSize = * ;//128KB
#endregion
#region props
/// <summary>
/// 当文件数据上传完成时发生
/// </summary>
public event UploadCompletedEventHandler UploadCompleted;
/// <summary>
/// 获取或设置上传数据的缓冲区大小
/// </summary>
public int SendBufferSize
{
get { return _sendBufferSize; }
set
{
if (value < )
value = * ;
_lok.AcquireWriterLock();
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()) >= )
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 = ;
IList<FtpDirectoryDetails> fddes = new List<FtpDirectoryDetails>();
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 == )
{
object[] tmp = new object[];
mc[].Groups.CopyTo(tmp, );
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[] { FtpDirectoryAccess.None, FtpDirectoryAccess.None, FtpDirectoryAccess.None }; Count = short.Parse(details[].ToString());
User = details[].ToString();
Group = details[].ToString(); Size = long.Parse(details[].ToString()); LastModified = DateTime.MinValue; Name = details[].ToString();
//
SetType(details[].ToString());
SetAccess(details[].ToString());
SetLastModified(details[].ToString(), details[].ToString(), details[].ToString());
} private void SetLastModified(string month, string day, string time0year)
{
StringBuilder sb = new StringBuilder();
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 - ] <= )//最后一位是数字
return month; if (month[] <= )//第一位是数字
return month.Substring(, month.Length - ); if ("January".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//Jan
return ;
else if ("February".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//Feb
return ;
else if ("March".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//Mar
return ;
else if ("April".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//Apr
return ;
else if ("May".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//May
return ;
else if ("June".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//Jun
return ;
else if ("July".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//Jul
return ;
else if ("August".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//Aug
return ;
else if ("September".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//Sep
return ;
else if ("October".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//Oct
return ;
else if ("November".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//Nov
return ;
else
//("December".StartsWith(month, StringComparison.CurrentCultureIgnoreCase))//Dec
return ;
} private void SetAccess(string access)
{
for (int i = ; i < access.Length; i += )
{
FtpDirectoryAccess acc = FtpDirectoryAccess.None;
for (int j = i; j < (i + ); 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 / ] = 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 = )
{
CheckUrl(file, withUnique);
FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read);
if (offset > )
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 == )
request.Method = WebRequestMethods.Ftp.UploadFileWithUniqueName;
else
request.Method = offset > ? 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() != -)
{
byte[] bt = reader.ReadBytes(_sendBufferSize);
stream.Write(bt, , 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();
UploadCompleted(new object(),
new UploadCompletedEventArgs()
{
Length = (!withUnique && IsUploadCheck) ? GetFileSize(path) : -,//异步时文件路径会改变
Path = path,
FileName = (!withUnique) ? Path.GetFileName(path) : string.Empty,
UploadStatus = status
});
}
}
}
protected void AsyncUploadCommon(string file, long offset = , bool withUnique = false)
{
CheckUrl(file, withUnique);
FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read);
if (offset > )
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 == )
request.Method = WebRequestMethods.Ftp.UploadFileWithUniqueName;
else
request.Method = offset > ? 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, , bt.Length);
if (length == ) break;
IAsyncResult iar = state.Stream.BeginWrite(bt, , 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();
UploadCompleted(new object(),
new UploadCompletedEventArgs()
{
Length = (!withUnique && IsUploadCheck) ? GetFileSize(path) : -,//异步时文件路径会改变
Path = path,
FileName = (!withUnique) ? Path.GetFileName(path) : string.Empty,
UploadStatus = status
});
}
}
}
#endregion

辅助函数

        private int DynamicBufferSize(int length)
{
if (length == )
length += DYNAMICIMCEPTVALUE;
if (length == _dynamicBufferSize)
length += DYNAMICINCREASEVALUE;
length += -_dynamicBufferSize;
if ((length + _dynamicBufferSize) <= )
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()) >= )
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()) >= )
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:\Users\Administrator\Desktop\FtpEntity\FtpEntity");
}
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