using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
namespace Common
{
/// <summary>
/// FTP类
/// </summary>
public class FTP
{
private string _ftpServerIP;
private string _ftpUserName;
private string _ftpPassword;
private Uri ftpUri;
private string _path;
/// <summary>
///
/// </summary>
/// <param name="ftpServerIp">ip:port,默认21端口可以只写ip</param>
/// <param name="username"></param>
/// <param name="passwd"></param>
public FTP(string ftpServerIp, string username, string passwd)
{
_ftpServerIP = ftpServerIp;
_ftpUserName = username;
_ftpPassword = passwd;
this.ftpUri = new Uri("ftp://" + ftpServerIp);
}
/// <summary>
///
/// </summary>
/// <param name="ftpServerIp">ip:port,默认21端口可以只写ip</param>
/// <param name="username"></param>
/// <param name="passwd"></param>
/// <param name="ftp_path"></param>
public FTP(string ftpServerIp, string username, string passwd, string ftp_path) : this(ftpServerIp, username, passwd)
{
_path = ftp_path;
this.ftpUri = new Uri("ftp://" + ftpServerIp + "/" + ftp_path);
}
/// <summary>
/// 获取文件及文件夹列表
/// </summary>
/// <returns></returns>
public List<FileStruct> GetList()
{
string dataString = GetFiles();
DirectoryListParser parser = new DirectoryListParser(dataString);
return parser.MyListArray;
}
/// <summary>
/// 获得当前文件夹下的所有文件夹
/// </summary>
/// <returns></returns>
public List<string> GetAllFolder()
{
string dataString = GetFiles();
DirectoryListParser parser = new DirectoryListParser(dataString);
List<string> result = new List<string>();
parser.DirectoryList.ForEach(x => result.Add(x.Name));
return result;
}
/// <summary>
/// 获得当前文件夹下的所有文件
/// </summary>
/// <returns></returns>
public List<string> GetAllFiles()
{
string dataString = GetFiles();
DirectoryListParser parser = new DirectoryListParser(dataString);
List<string> result = new List<string>();
parser.FileList.ForEach(x => result.Add(x.Name));
return result;
}
private string GetFiles()
{
WebRequest listRequest = WebRequest.Create(ftpUri);
listRequest.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
listRequest.Credentials = new NetworkCredential(_ftpUserName, _ftpPassword);
WebResponse listResponse = listRequest.GetResponse();
Stream responseStream = listResponse.GetResponseStream();
StreamReader readStream = new StreamReader(responseStream, Encoding.UTF8);
string result = "";
if (readStream != null) result = readStream.ReadToEnd();
listResponse.Close();
responseStream.Close();
readStream.Close();
return result;
}
/// <summary>
/// 创建文件夹
/// </summary>
/// <param name="dirName">目录,如"aa/cc/bb",只创建bb文件夹</param>
public bool MakeDir(string dirName)
{
bool success = TryMakeDir(dirName);
if (!success)
{
success = TryMakeDir(dirName);
if (!success) success = TryMakeDir(dirName, true);
}
return success;
}
private bool TryMakeDir(string dirName, bool writeLog = false)
{
try
{
var reqFTP = WebRequest.Create(new Uri(ftpUri + "/" + dirName));
reqFTP.Method = WebRequestMethods.Ftp.MakeDirectory;
reqFTP.Credentials = new NetworkCredential(_ftpUserName, _ftpPassword);
WebResponse response = reqFTP.GetResponse();
Stream ftpStream = response.GetResponseStream();
ftpStream.Close();
response.Close();
return true;
}
catch (Exception ex)
{
if (writeLog) LogHelper.logger.Error(ex);
return false;
}
}
/// <summary>
/// 上传文件
/// </summary>
/// <param name="localFile"></param>
/// <param name="remoteFileName"></param>
/// <returns></returns>
public bool Upload(string localFileName, string remoteFileName)
{
bool success = TryUpload(localFileName, remoteFileName);
if (!success)
{
success = TryUpload(localFileName, remoteFileName);
if (!success) success = TryUpload(localFileName, remoteFileName, true);
}
return success;
}
private bool TryUpload(string localFileName, string remoteFileName, bool writeLog = false)
{
try
{
string uri = string.Empty;
if (this.ftpUri.ToString().EndsWith("/")) uri = this.ftpUri + remoteFileName;
else uri = this.ftpUri + "/" + remoteFileName;
WebClient myWebClient = new WebClient();
myWebClient.Credentials = new NetworkCredential(_ftpUserName, _ftpPassword);
byte[] responseArray = myWebClient.UploadFile(uri, localFileName);
return true;
}
catch (Exception ex)
{
if (writeLog) LogHelper.logger.Error($"Upload({localFileName},{remoteFileName})", ex);
return false;
}
}
/// <summary>
/// 追加文件内容到远端文件,如果远端文件不存在则上传
/// </summary>
/// <param name="localFileName">本地文件,如"D:\\aa.txt"</param>
/// <param name="remoteFileName">ftp文件,如"A/B/b.txt"</param>
public void AppendFile(string localFileName, string remoteFileName)
{
try
{
if (!File.Exists(localFileName)) return;
FileInfo fileInf = new FileInfo(localFileName);
string uri = $"ftp://{_ftpServerIP}/{_path}/{remoteFileName}";
var reqFTP = WebRequest.Create(new Uri(uri));
reqFTP.Credentials = new NetworkCredential(_ftpUserName, _ftpPassword);
reqFTP.Method = WebRequestMethods.Ftp.AppendFile;
reqFTP.ContentLength = fileInf.Length;
int buffLength = 2048;
byte[] buff = new byte[buffLength];
int contentLen;
using (FileStream fs = fileInf.OpenRead())
using (Stream strm = reqFTP.GetRequestStream())
{
contentLen = fs.Read(buff, 0, buffLength);
while (contentLen != 0)
{
strm.Write(buff, 0, contentLen);
contentLen = fs.Read(buff, 0, buffLength);
}
}
}
catch (Exception ex)
{
LogHelper.logger.Error(ex);
}
}
/// <summary>
/// 删除文件
/// </summary>
/// <param name="fileName">文件名,如“A/B/b.txt”</param>
public bool Delete(string fileName)
{
try
{
string uri = $"ftp://{_ftpServerIP}/{_path}/{fileName}";
var reqFTP = WebRequest.Create(new Uri(uri));
reqFTP.Credentials = new NetworkCredential(_ftpUserName, _ftpPassword);
reqFTP.Method = WebRequestMethods.Ftp.DeleteFile;
string result = String.Empty;
using (var response = reqFTP.GetResponse())
using (Stream datastream = response.GetResponseStream())
using (StreamReader sr = new StreamReader(datastream))
{
result = sr.ReadToEnd();
}
return true;
}
catch (Exception ex)
{
LogHelper.logger.Error(ex);
return false;
}
}
/// <summary>
/// 重命名目录
/// </summary>
/// <param name="currentFilename">原来名称</param>
/// <param name="newFilename">新名称</param>
public bool ReName(string currentFilename, string newFilename)
{
FtpWebRequest reqFTP;
try
{
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(ftpUri + currentFilename));
reqFTP.Method = WebRequestMethods.Ftp.Rename;
reqFTP.RenameTo = newFilename;
reqFTP.UseBinary = true;
reqFTP.Credentials = new NetworkCredential(_ftpUserName, _ftpPassword);
FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
Stream ftpStream = response.GetResponseStream();
ftpStream.Close();
response.Close();
return true;
}
catch (Exception ex)
{
LogHelper.logger.Error(ex);
return false;
}
}
/// <summary>
/// 判断目录是否存在
/// </summary>
/// <param name="path">文件夹所在目录,如:"aa/bb"</param>
/// <param name="FolderName">文件夹名称,如:"cc"</param>
/// <returns></returns>
public bool DirectoryExist(string path, string FolderName)
{
try
{
string uri = $"ftp://{_ftpServerIP}/{_path}/{path}";
WebRequest reqFTP = WebRequest.Create(new Uri(uri));
reqFTP.Credentials = new NetworkCredential(this._ftpUserName, this._ftpPassword);
reqFTP.Method = WebRequestMethods.Ftp.ListDirectory;
WebResponse response = reqFTP.GetResponse();
string result = "";
StreamReader readStream = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
if (readStream != null)
{
result = readStream.ReadToEnd();
}
response.Close();
LogHelper.logger.Debug($"DirectoryExist({path}, {FolderName}) return {result}");
int index = result.IndexOf(FolderName + "\r\n");
return (index == 0 || (index > 0 && result.Substring(index - 1, 1) == "\n"));
}
catch
{
return false;
}
}
public bool DirectoryExist_ServerU(string path)
{
string uri = $"ftp://{_ftpServerIP}/{_path}/{path}";
FtpWebRequest reqFtp = (FtpWebRequest)FtpWebRequest.Create(new Uri(uri));
reqFtp.UseBinary = true;
reqFtp.Credentials = new NetworkCredential(_ftpUserName, _ftpPassword);
reqFtp.Method = WebRequestMethods.Ftp.ListDirectory;
FtpWebResponse resFtp = null;
try
{
resFtp = (FtpWebResponse)reqFtp.GetResponse();
FtpStatusCode code = resFtp.StatusCode;
resFtp.Close();
return true;
}
catch
{
if(resFtp != null) resFtp.Close();
return false;
}
}
/// <summary>
/// 删除文件夹
/// </summary>
/// <param name="folderName"></param>
public bool RemoveDirectory(string folderName)
{
try
{
string uri = ftpUri + "/" + folderName;
FtpWebRequest reqFTP;
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(uri));
//reqFTP.EnableSsl = false;
reqFTP.Credentials = new NetworkCredential(_ftpUserName, _ftpPassword);
reqFTP.KeepAlive = false;
reqFTP.Method = WebRequestMethods.Ftp.RemoveDirectory;
string result = String.Empty;
FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
long size = response.ContentLength;
Stream datastream = response.GetResponseStream();
StreamReader sr = new StreamReader(datastream);
result = sr.ReadToEnd();
sr.Close();
datastream.Close();
response.Close();
return true;
}
catch (Exception ex)
{
LogHelper.logger.Error(ex);
return false;
}
}
public bool DownFile(string fileName, string localName)
{
try
{
string uri = string.Empty;
if (this.ftpUri.ToString().EndsWith("/")) uri = this.ftpUri + fileName;
else uri = this.ftpUri + "/" + fileName;
WebClient myWebClient = new WebClient();
myWebClient.Credentials = new NetworkCredential(_ftpUserName, _ftpPassword);
myWebClient.DownloadFile(uri, localName);
return File.Exists(localName);
}
catch (Exception ex)
{
LogHelper.logger.Error(fileName, ex);
return false;
}
}
}
public struct FileStruct
{
/// <summary>
/// 所有者
/// </summary>
public string Owner;
/// <summary>
/// 是否为目录
/// </summary>
public bool IsDirectory;
/// <summary>
/// 更新时间
/// </summary>
public string CreateTime;
/// <summary>
/// 名称
/// </summary>
public string Name;
/// <summary>
/// 文件大小
/// </summary>
public int FileSize;
/// <summary>
/// 类型
/// </summary>
public string FileType;
}
public class DirectoryListParser
{
private List<FileStruct> _myListArray;
public DirectoryListParser(string responseString)
{
_myListArray = GetList(responseString);
}
public List<FileStruct> MyListArray { get { return _myListArray; } }
/// <summary>
/// 文件列表
/// </summary>
public List<FileStruct> FileList { get { return _myListArray.Where(x => !x.IsDirectory).ToList(); } }
/// <summary>
/// 目录列表
/// </summary>
public List<FileStruct> DirectoryList { get { return _myListArray.Where(x => x.IsDirectory).ToList(); } }
private List<FileStruct> GetList(string datastring)
{
List<FileStruct> myListArray = new List<FileStruct>();
string[] dataRecords = datastring.Split('\n');
int style = GetFileListStyle(dataRecords);
foreach (string s in dataRecords)
{
if (style > 0 && s != "")
{
FileStruct f = new FileStruct();
f.Name = "..";
if (style == 1) f = ParseFileStructFromUnixStyleRecord(s);
else if (style == 2) f = ParseFileStructFromWindowsStyleRecord(s);
if (f.Name != "" && f.Name != "." && f.Name != "..") myListArray.Add(f);
}
}
return myListArray;
}
/// <summary>
/// 获取文件风格
/// </summary>
/// <param name="recordList"></param>
/// <returns>0-未知,1-Unix风格,2-Windows风格</returns>
public int GetFileListStyle(string[] recordList)
{
foreach (string s in recordList)
{
if (s.Length > 10 && Regex.IsMatch(s.Substring(0, 10), "(-|d)((-|r)(-|w)(-|x)){3}")) return 1;
else if (s.Length > 8 && Regex.IsMatch(s.Substring(0, 8), "[0-9]{2}-[0-9]{2}-[0-9]{2}")) return 2;
}
return 0;
}
private FileStruct ParseFileStructFromWindowsStyleRecord(string Record)
{
// Assuming the record style as
//文件夹 02-03-04 07:46PM <DIR> Append
//文件 02-12-11 02:20AM 26599 xxd.asp
FileStruct f = new FileStruct();
string[] arr = Regex.Split(Record.Trim(), "\\s+");
f.Name = arr[3];
f.CreateTime = arr[0] + " " + arr[1];
if (arr[2] == "<DIR>")
{
f.FileSize = 0;
f.IsDirectory = true;
f.FileType = "文件夹";
}
else
{
f.FileSize = int.Parse(arr[2]);
f.IsDirectory = false;
if (arr[3].IndexOf(".") > -1) f.FileType = arr[3].Split('.')[1];
else f.FileType = "未知";
}
return f;
}
private FileStruct ParseFileStructFromUnixStyleRecord(string record)
{
///Assuming record style as
/// dr-xr-xr-x 1 owner group 0 Nov 25 2002 bussys
FileStruct f = new FileStruct();
if (record[0] == '-' || record[0] == 'd')
{// its a valid file record
string processstr = record.Trim();
var flag = processstr.Substring(0, 9);
f.IsDirectory = (flag[0] == 'd');
processstr = (processstr.Substring(11)).Trim();
_cutSubstringFromStringWithTrim(ref processstr, ' ', 0); //skip one part
f.Owner = _cutSubstringFromStringWithTrim(ref processstr, ' ', 0);
f.CreateTime = getCreateTimeString(record);
int fileNameIndex = record.IndexOf(f.CreateTime) + f.CreateTime.Length;
f.Name = record.Substring(fileNameIndex).Trim(); //Rest of the part is name
}
else f.Name = string.Empty;
return f;
}
private string getCreateTimeString(string record)
{
//Does just basic datetime string validation for demo, not an accurate check
//on date and time fields
string month = "(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)";
string space = @"(\040)+";
string day = "([0-9]|[1-3][0-9])";
string year = "[1-2][0-9]{3}";
string time = "[0-9]{1,2}:[0-9]{2}";
Regex dateTimeRegex = new Regex(month + space + day + space + "(" + year + "|" + time + ")", RegexOptions.IgnoreCase);
Match match = dateTimeRegex.Match(record);
return match.Value;
}
private string _cutSubstringFromStringWithTrim(ref string s, char c, int startIndex)
{
int pos1 = s.IndexOf(c, startIndex);
string retString = s.Substring(0, pos1);
s = (s.Substring(pos1)).Trim();
return retString;
}
}
}