csharp: FTP Client Library using System.Net.FtpWebRequest
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Collections;
using Microsoft.VisualBasic;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;
using System.Windows.Forms;
//https://www.codeproject.com/Articles/56321/A-Windows-FTP-Application
//https://www.codeproject.com/Articles/4472/Enhanced-BrowseForFolder-styled-TreeView
//https://github.com/ChrisRichner/TreeViewFolderBrowser
//https://www.codeproject.com/Articles/11991/An-FTP-client-library-for-NET
//https://github.com/aybe/Windows-API-Code-Pack-1.1
//https://github.com/dbarros/WindowsAPICodePack namespace FTPLibrary
{
#region "FTP client class"
/// <summary>
/// A wrapper class for .NET 2.0 FTP
/// </summary>
/// <remarks>
/// This class does not hold open an FTP connection but
/// instead is stateless: for each FTP request it
/// connects, performs the request and disconnects.
/// </remarks>
public class FTPclient
{
#region Delegated & Events
//Download Progress Changed Event
public delegate void DownloadProgressChangedHandler(object sender, DownloadProgressChangedArgs e);
public event DownloadProgressChangedHandler OnDownloadProgressChanged; //Download Completed Event
public delegate void DownloadCompletedHandler(object sender, DownloadCompletedArgs e);
public event DownloadCompletedHandler OnDownloadCompleted; //New Server Message Event
public delegate void NewMessageHandler(object sender, NewMessageEventArgs e);
public event NewMessageHandler OnNewMessageReceived; //Upload Progress Changed Event
//Download Progress Changed Event
public delegate void UploadProgressChangedHandler(object sender, UploadProgressChangedArgs e);
public event UploadProgressChangedHandler OnUploadProgressChanged; //Upload Completed Event
public delegate void UploadCompletedHandler(object sender, UploadCompletedArgs e);
public event UploadCompletedHandler OnUploadCompleted;
#endregion #region "CONSTRUCTORS"
/// <summary>
/// Blank constructor
/// </summary>
/// <remarks>Hostname, username and password must be set manually</remarks>
public FTPclient()
{
} /// <summary>
/// Constructor just taking the hostname
/// </summary>
/// <param name="Hostname">in either ftp://ftp.host.com or ftp.host.com form</param>
/// <remarks></remarks>
public FTPclient(string Hostname)
{
_hostname = Hostname;
} /// <summary>
/// Constructor taking hostname, username and password
/// </summary>
/// <param name="Hostname">in either ftp://ftp.host.com or ftp.host.com form</param>
/// <param name="Username">Leave blank to use 'anonymous' but set password to your email</param>
/// <param name="Password"></param>
/// <remarks></remarks>
public FTPclient(string Hostname, string Username, string Password)
{
_hostname = Hostname;
_username = Username;
_password = Password;
}
#endregion #region "Directory functions"
/// <summary>
/// Return a simple directory listing
/// </summary>
/// <param name="directory">Directory to list, e.g. /pub</param>
/// <returns>A list of filenames and directories as a List(of String)</returns>
/// <remarks>For a detailed directory listing, use ListDirectoryDetail</remarks>
public List<string> ListDirectory(string directory)
{
//return a simple list of filenames in directory
System.Net.FtpWebRequest ftp = GetRequest(GetDirectory(directory));
//Set request to do simple list
ftp.Method = System.Net.WebRequestMethods.Ftp.ListDirectory;
//Give Message of Command
NewMessageEventArgs e = new NewMessageEventArgs("COMMAND", "List Directory", "NLST");
OnNewMessageReceived(this, e); string str = GetStringResponse(ftp);
//replace CRLF to CR, remove last instance
str = str.Replace("\r\n", "\r").TrimEnd('\r');
//split the string into a list
List<string> result = new List<string>();
result.AddRange(str.Split('\r'));
return result;
} /// <summary>
/// Return a detailed directory listing
/// </summary>
/// <param name="directory">Directory to list, e.g. /pub/etc</param>
/// <returns>An FTPDirectory object</returns>
public FTPdirectory ListDirectoryDetail(string directory)
{
System.Net.FtpWebRequest ftp = GetRequest(GetDirectory(directory));
//Set request to do simple list
ftp.Method = System.Net.WebRequestMethods.Ftp.ListDirectoryDetails;
ftp.UseBinary = true;
//Give Message of Command
NewMessageEventArgs e = new NewMessageEventArgs("COMMAND", "List Directory Details", "LIST");
OnNewMessageReceived(this, e);
string str = GetStringResponse(ftp);
//replace CRLF to CR, remove last instance
str = str.Replace("\r\n", "\r").TrimEnd('\r');
//split the string into a list
return new FTPdirectory(str, _lastDirectory);
} #endregion #region "Upload: File transfer TO ftp server"
/// <summary>
/// Copy a local file to the FTP server
/// </summary>
/// <param name="localFilename">Full path of the local file</param>
/// <param name="targetFilename">Target filename, if required</param>
/// <returns></returns>
/// <remarks>If the target filename is blank, the source filename is used
/// (assumes current directory). Otherwise use a filename to specify a name
/// or a full path and filename if required.</remarks>
public bool Upload(string localFilename, string targetFilename)
{
//1. check source
if (!File.Exists(localFilename))
{
throw (new ApplicationException("File " + localFilename + " not found"));
}
//copy to FI
FileInfo fi = new FileInfo(localFilename);
return Upload(fi, targetFilename);
} #region Upload Variables
System.Net.FtpWebRequest UploadFTPRequest = null;
FileStream UploadFileStream = null;
Stream UploadStream = null;
bool UploadCanceled = false;
FileInfo UploadFileInfo = null;
#endregion /// <summary>
/// Upload a local file to the FTP server
/// </summary>
/// <param name="fi">Source file</param>
/// <param name="targetFilename">Target filename (optional)</param>
/// <returns></returns>
public bool Upload(FileInfo fi, string targetFilename)
{
//copy the file specified to target file: target file can be full path or just filename (uses current dir) //1. check target
string target;
if (targetFilename.Trim() == "")
{
//Blank target: use source filename & current dir
target = this.CurrentDirectory + fi.Name;
}
else if (targetFilename.Contains("/"))
{
//If contains / treat as a full path
target = AdjustDir(targetFilename);
}
else
{
//otherwise treat as filename only, use current directory
target = CurrentDirectory + targetFilename;
} string URI = Hostname + target;
//perform copy
UploadFTPRequest = GetRequest(URI); //Set request to upload a file in binary
UploadFTPRequest.Method = System.Net.WebRequestMethods.Ftp.UploadFile;
UploadFTPRequest.UseBinary = true;
//Notify FTP of the expected size
UploadFTPRequest.ContentLength = fi.Length;
UploadFileInfo = fi; //create byte array to store: ensure at least 1 byte!
const int BufferSize = 2048;
byte[] content = new byte[BufferSize - 1 + 1];
int dataRead; //open file for reading
using (UploadFileStream = fi.OpenRead())
{
try
{
//open request to send
using (UploadStream = UploadFTPRequest.GetRequestStream())
{
//Give Message of Command
NewMessageEventArgs e = new NewMessageEventArgs("COMMAND", "Upload File", "STOR");
OnNewMessageReceived(this, e); //Get File Size
Int64 TotalBytesUploaded = 0;
Int64 FileSize = fi.Length;
do
{
if (UploadCanceled)
{
NewMessageEventArgs CancelMessage = new NewMessageEventArgs("RESPONSE", "Upload Canceled.", "CANCEL");
OnNewMessageReceived(this, CancelMessage);
UploadCanceled = false;
return false;
} dataRead = UploadFileStream.Read(content, 0, BufferSize);
UploadStream.Write(content, 0, dataRead);
TotalBytesUploaded += dataRead;
//Declare Event
UploadProgressChangedArgs DownloadProgress = new UploadProgressChangedArgs(TotalBytesUploaded, FileSize); //Progress changed, Raise the event.
OnUploadProgressChanged(this, DownloadProgress); System.Windows.Forms.Application.DoEvents();
} while (!(dataRead < BufferSize)); //Get Message and Raise Event
NewMessageEventArgs UPloadResponse = new NewMessageEventArgs("RESPONSE", "File Uploaded!", "STOR");
OnNewMessageReceived(this, UPloadResponse); //Declare Event
UploadCompletedArgs Args = new UploadCompletedArgs("Successful", true);
//Raise Event
OnUploadCompleted(this, Args); UploadStream.Close();
} }
catch (Exception ex)
{
//Declare Event
UploadCompletedArgs Args = new UploadCompletedArgs("Error: " + ex.Message, false);
//Raise Event
OnUploadCompleted(this, Args);
}
finally
{
//ensure file closed
UploadFileStream.Close();
} } UploadFTPRequest = null;
return true; } public void CancelUpload(string UploadFileName)
{
if (UploadFileStream != null)
{
UploadFileStream.Close();
UploadFTPRequest.Abort();
//UploadFileInfo.Delete();
UploadCanceled = true;
UploadFTPRequest = null;
this.FtpDelete(UploadFileName);
MessageBox.Show("Upload Canceled");
}
}
#endregion #region "Download: File transfer FROM ftp server"
/// <summary>
/// Copy a file from FTP server to local
/// </summary>
/// <param name="sourceFilename">Target filename, if required</param>
/// <param name="localFilename">Full path of the local file</param>
/// <returns></returns>
/// <remarks>Target can be blank (use same filename), or just a filename
/// (assumes current directory) or a full path and filename</remarks>
public bool Download(string sourceFilename, string localFilename, bool PermitOverwrite)
{
//2. determine target file
FileInfo fi = new FileInfo(localFilename);
return this.Download(sourceFilename, fi, PermitOverwrite);
} //Version taking an FtpFileInfo
public bool Download(FTPfileInfo file, string localFilename, bool PermitOverwrite)
{
return this.Download(file.FullName, localFilename, PermitOverwrite);
} //Another version taking FtpFileInfo and FileInfo
public bool Download(FTPfileInfo file, FileInfo localFI, bool PermitOverwrite)
{
return this.Download(file.FullName, localFI, PermitOverwrite);
} #region Download Variables
System.Net.FtpWebRequest DownloadFTPRequest = null;
FtpWebResponse DownloadResponse = null;
Stream DownloadResponseStream = null; //中文亂碼
FileStream DownloadFileStream = null;
FileInfo TargetFileInfo = null;
bool DownloadCanceled = false;
#endregion
//Version taking string/FileInfo
public bool Download(string sourceFilename, FileInfo targetFI, bool PermitOverwrite)
{
//1. check target
if (targetFI.Exists && !(PermitOverwrite))
{
throw (new ApplicationException("Target file already exists"));
} //2. check source
string target;
if (sourceFilename.Trim() == "")
{
throw (new ApplicationException("File not specified"));
}
else if (sourceFilename.Contains("/"))
{
//treat as a full path
target = AdjustDir(sourceFilename);
}
else
{
//treat as filename only, use current directory
target = CurrentDirectory + sourceFilename;
} string URI = Hostname + target; //3. perform copy
DownloadFTPRequest = GetRequest(URI); //Set request to download a file in binary mode
DownloadFTPRequest.Method = System.Net.WebRequestMethods.Ftp.DownloadFile;
DownloadFTPRequest.UseBinary = true;
TargetFileInfo = targetFI;
//open request and get response stream
using (DownloadResponse = (FtpWebResponse)DownloadFTPRequest.GetResponse())
{
using (DownloadResponseStream = DownloadResponse.GetResponseStream())
{
//System.Security.AccessControl.FileSecurity fileSecurity = new System.Security.AccessControl.FileSecurity(targetFI.FullName, System.Security.AccessControl.AccessControlSections.All);
//targetFI.SetAccessControl(fileSecurity);
//loop to read & write to file
using (DownloadFileStream = new FileStream(targetFI.FullName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
try
{
//Give Message of Command
NewMessageEventArgs e = new NewMessageEventArgs("COMMAND", "Download File", "RETR");
OnNewMessageReceived(this, e);
byte[] buffer = new byte[2048];
int read = 0;
Int64 TotalBytesRead = 0;
Int64 FileSize = this.GetFileSize(sourceFilename);
DownloadCanceled = false;
do
{
if (DownloadCanceled)
{
NewMessageEventArgs CancelMessage = new NewMessageEventArgs("RESPONSE", "Download Canceled.", "CANCEL"); DownloadCanceled = false;
OnNewMessageReceived(this, CancelMessage);
return false;
} read = DownloadResponseStream.Read(buffer, 0, buffer.Length);
DownloadFileStream.Write(buffer, 0, read);
TotalBytesRead += read;
//Declare Event
DownloadProgressChangedArgs DownloadProgress = new DownloadProgressChangedArgs(TotalBytesRead, FileSize); //Progress changed, Raise the event.
OnDownloadProgressChanged(this, DownloadProgress); System.Windows.Forms.Application.DoEvents(); } while (!(read == 0)); //Get Message and Raise Event
NewMessageEventArgs NewMessageArgs = new NewMessageEventArgs("RESPONSE", DownloadResponse.StatusDescription, DownloadResponse.StatusCode.ToString());
OnNewMessageReceived(this, NewMessageArgs); //Declare Event
DownloadCompletedArgs Args = new DownloadCompletedArgs("Successful", true);
//Raise Event
OnDownloadCompleted(this, Args); DownloadResponseStream.Close();
DownloadFileStream.Flush();
DownloadFileStream.Close();
DownloadFileStream = null;
DownloadResponseStream = null;
}
catch (Exception ex)
{
//catch error and delete file only partially downloaded
DownloadFileStream.Close();
//delete target file as it's incomplete
targetFI.Delete(); //Decalre Event for Error
DownloadCompletedArgs DownloadCompleted = new DownloadCompletedArgs("Error: " + ex.Message, false);
//Raise Event
OnDownloadCompleted(this, DownloadCompleted);
}
}
if (DownloadFileStream != null)
DownloadResponseStream.Close();
}
if (DownloadFileStream != null)
DownloadResponse.Close();
}
return true;
} public void CancelDownload()
{
if (DownloadFileStream != null)
{
DownloadFileStream.Close(); DownloadFTPRequest.Abort(); DownloadResponse.Close();
DownloadResponseStream.Close();
//DownloadFileStream = null;
//DownloadResponseStream = null;
TargetFileInfo.Delete();
DownloadCanceled = true;
MessageBox.Show("Download Canceled");
}
}
#endregion #region "Other functions: Delete rename etc."
/// <summary>
/// Delete remote file
/// </summary>
/// <param name="filename">filename or full path</param>
/// <returns></returns>
/// <remarks></remarks>
public bool FtpDelete(string filename)
{
//Determine if file or full path
string URI = this.Hostname + GetFullPath(filename); System.Net.FtpWebRequest ftp = GetRequest(URI);
//Set request to delete
ftp.Method = System.Net.WebRequestMethods.Ftp.DeleteFile;
try
{
//get response but ignore it
string str = GetStringResponse(ftp);
//Give Message of Command
NewMessageEventArgs e = new NewMessageEventArgs("COMMAND", "Delete File", "DELE");
OnNewMessageReceived(this, e);
}
catch (Exception)
{
return false;
}
return true;
} /// <summary>
/// Determine if file exists on remote FTP site
/// </summary>
/// <param name="filename">Filename (for current dir) or full path</param>
/// <returns></returns>
/// <remarks>Note this only works for files</remarks>
public bool FtpFileExists(string filename)
{
//Try to obtain filesize: if we get error msg containing "550"
//the file does not exist
try
{
long size = GetFileSize(filename);
return true; }
catch (Exception ex)
{
//only handle expected not-found exception
if (ex is System.Net.WebException)
{
//file does not exist/no rights error = 550
if (ex.Message.Contains("550"))
{
//clear
return false;
}
else
{
System.Windows.Forms.MessageBox.Show(ex.Message);
return false;
}
}
else
{
System.Windows.Forms.MessageBox.Show(ex.Message);
return false;
}
}
} /// <summary>
/// Determine size of remote file
/// </summary>
/// <param name="filename"></param>
/// <returns></returns>
/// <remarks>Throws an exception if file does not exist</remarks>
public long GetFileSize(string filename)
{
string path;
if (filename.Contains("/"))
{
path = AdjustDir(filename);
}
else
{
path = this.CurrentDirectory + filename;
}
string URI = this.Hostname + path;
System.Net.FtpWebRequest ftp = GetRequest(URI);
//Try to get info on file/dir?
ftp.Method = System.Net.WebRequestMethods.Ftp.GetFileSize;
string tmp = this.GetStringResponse(ftp);
//Give Message of Command
NewMessageEventArgs e = new NewMessageEventArgs("COMMAND", "Get File Size", "SIZE");
OnNewMessageReceived(this, e);
return GetSize(ftp);
} public bool FtpRename(string sourceFilename, string newName)
{
//Does file exist?
string source = GetFullPath(sourceFilename);
if (!FtpFileExists(source))
{
throw (new FileNotFoundException("File " + source + " not found"));
} //build target name, ensure it does not exist
string target = GetFullPath(newName);
if (target == source)
{
throw (new ApplicationException("Source and target are the same"));
}
else if (FtpFileExists(target))
{
throw (new ApplicationException("Target file " + target + " already exists"));
} //perform rename
string URI = this.Hostname + source; System.Net.FtpWebRequest ftp = GetRequest(URI);
//Set request to delete
ftp.Method = System.Net.WebRequestMethods.Ftp.Rename;
ftp.RenameTo = target;
ftp.UseBinary = true; try
{
//get response but ignore it
string str = GetStringResponse(ftp);
//Give Message of Command
NewMessageEventArgs e = new NewMessageEventArgs("COMMAND", "File Rename", "RENAME");
OnNewMessageReceived(this, e);
}
catch (Exception)
{
return false;
}
return true;
} public bool FtpCreateDirectory(string dirpath)
{
//perform create
string URI = this.Hostname + AdjustDir(dirpath);
System.Net.FtpWebRequest ftp = GetRequest(URI);
//Set request to MkDir
ftp.Method = System.Net.WebRequestMethods.Ftp.MakeDirectory;
try
{
//get response but ignore it
string str = GetStringResponse(ftp);
//Give Message of Command
NewMessageEventArgs e = new NewMessageEventArgs("COMMAND", "Make Directory", "MKD");
OnNewMessageReceived(this, e);
}
catch (Exception)
{
return false;
}
return true;
} public bool FtpDeleteDirectory(string dirpath)
{
//perform remove
string URI = this.Hostname + AdjustDir(dirpath);
System.Net.FtpWebRequest ftp = GetRequest(URI);
ftp.UseBinary = true;
//Set request to RmDir
ftp.Method = System.Net.WebRequestMethods.Ftp.RemoveDirectory;
try
{
//get response but ignore it
string str = GetStringResponse(ftp);
//Give Message of Command
NewMessageEventArgs e = new NewMessageEventArgs("COMMAND", "Remove Directory", "RMD");
OnNewMessageReceived(this, e);
}
catch (Exception)
{
return false;
}
return true;
}
#endregion #region "private supporting fns"
//Get the basic FtpWebRequest object with the
//common settings and security
private FtpWebRequest GetRequest(string URI)
{
//create request
FtpWebRequest result = (FtpWebRequest)FtpWebRequest.Create(URI);
//Set the login details
result.Credentials = GetCredentials();
//Do not keep alive (stateless mode)
result.KeepAlive = false;
result.UseBinary = true;
return result;
} /// <summary>
/// Get the credentials from username/password
/// </summary>
private System.Net.ICredentials GetCredentials()
{
return new System.Net.NetworkCredential(Username, Password);
} /// <summary>
/// returns a full path using CurrentDirectory for a relative file reference
/// </summary>
private string GetFullPath(string file)
{
if (file.Contains("/"))
{
return AdjustDir(file);
}
else
{
return this.CurrentDirectory + file;
}
} /// <summary>
/// Amend an FTP path so that it always starts with /
/// </summary>
/// <param name="path">Path to adjust</param>
/// <returns></returns>
/// <remarks></remarks>
private string AdjustDir(string path)
{
return ((path.StartsWith("/")) ? "" : "/").ToString() + path;
} private string GetDirectory(string directory)
{
string URI;
if (directory == "")
{
//build from current
URI = Hostname + this.CurrentDirectory;
_lastDirectory = this.CurrentDirectory;
}
else
{
if (!directory.StartsWith("/"))
{
throw (new ApplicationException("Directory should start with /"));
}
URI = this.Hostname + directory;
_lastDirectory = directory;
}
return URI;
} //stores last retrieved/set directory
private string _lastDirectory = ""; /// <summary>
/// Obtains a response stream as a string
/// </summary>
/// <param name="ftp">current FTP request</param>
/// <returns>String containing response</returns>
/// <remarks>FTP servers typically return strings with CR and
/// not CRLF. Use respons.Replace(vbCR, vbCRLF) to convert
/// to an MSDOS string</remarks>
private string GetStringResponse(FtpWebRequest ftp)
{
//Get the result, streaming to a string
string result = "";
using (FtpWebResponse response = (FtpWebResponse)ftp.GetResponse())
{
long size = response.ContentLength;
using (Stream datastream = response.GetResponseStream())
{
// 一中文亂碼問題 涂聚文 20180801
using (StreamReader sr = new StreamReader(datastream, System.Text.Encoding.GetEncoding("GB2312")))
{
_WelcomeMessage = response.WelcomeMessage;
_ExitMessage = response.ExitMessage;
result = sr.ReadToEnd();
sr.Close();
}
try
{
//Declare Event
NewMessageEventArgs e = new NewMessageEventArgs("RESPONSE", response.StatusDescription, response.StatusCode.ToString());
//Raise Event
OnNewMessageReceived(this, e);
}
catch
{ } datastream.Close();
}
response.Close();
}
return result;
} /// <summary>
/// Gets the size of an FTP request
/// </summary>
/// <param name="ftp"></param>
/// <returns></returns>
/// <remarks></remarks>
private long GetSize(FtpWebRequest ftp)
{
long size;
using (FtpWebResponse response = (FtpWebResponse)ftp.GetResponse())
{
size = response.ContentLength;
response.Close();
} return size;
}
#endregion #region "Properties"
private string _hostname;
/// <summary>
/// Hostname
/// </summary>
/// <value></value>
/// <remarks>Hostname can be in either the full URL format
/// ftp://ftp.myhost.com or just ftp.myhost.com
/// </remarks>
public string Hostname
{
get
{
if (_hostname.StartsWith("ftp://"))
{
return _hostname;
}
else
{
return "ftp://" + _hostname;
}
}
set
{
_hostname = value;
}
}
private string _username;
/// <summary>
/// Username property
/// </summary>
/// <value></value>
/// <remarks>Can be left blank, in which case 'anonymous' is returned</remarks>
public string Username
{
get
{
return (_username == "" ? "anonymous" : _username);
}
set
{
_username = value;
}
}
private string _password;
public string Password
{
get
{
return _password;
}
set
{
_password = value;
}
} /// <summary>
/// The CurrentDirectory value
/// </summary>
/// <remarks>Defaults to the root '/'</remarks>
private string _currentDirectory = "/";
public string CurrentDirectory
{
get
{
//return directory, ensure it ends with /
return _currentDirectory + ((_currentDirectory.EndsWith("/")) ? "" : "/").ToString();
}
set
{
if (!value.StartsWith("/"))
{
throw (new ApplicationException("Directory should start with /"));
}
_currentDirectory = value;
}
} #endregion #region Server Messages
string _WelcomeMessage, _ExitMessage;
public string WelcomeMessage
{
get
{
return _WelcomeMessage;
}
set
{
_WelcomeMessage = value;
}
}
public string ExitMessage
{
get
{
return _ExitMessage;
}
set
{
_ExitMessage = value;
}
}
#endregion }
#endregion #region "FTP file info class"
/// <summary>
/// Represents a file or directory entry from an FTP listing
/// </summary>
/// <remarks>
/// This class is used to parse the results from a detailed
/// directory list from FTP. It supports most formats of
/// </remarks>
public class FTPfileInfo
{ //Stores extended info about FTP file #region "Properties"
public string FullName
{
get
{
return Path + Filename;
}
}
public string Filename
{
get
{
return _filename;
}
}
public string Path
{
get
{
return _path;
}
}
public DirectoryEntryTypes FileType
{
get
{
return _fileType;
}
}
public long Size
{
get
{
return _size;
}
}
public DateTime FileDateTime
{
get
{
return _fileDateTime;
}
}
public string Permission
{
get
{
return _permission;
}
}
public string Extension
{
get
{
int i = this.Filename.LastIndexOf(".");
if (i >= 0 && i < (this.Filename.Length - 1))
{
return this.Filename.Substring(i + 1);
}
else
{
return "";
}
}
}
public string NameOnly
{
get
{
int i = this.Filename.LastIndexOf(".");
if (i > 0)
{
return this.Filename.Substring(0, i);
}
else
{
return this.Filename;
}
}
}
private string _filename;
private string _path;
private DirectoryEntryTypes _fileType;
private long _size;
private DateTime _fileDateTime;
private string _permission; #endregion /// <summary>
/// Identifies entry as either File or Directory
/// </summary>
public enum DirectoryEntryTypes
{
File,
Directory
} /// <summary>
/// Constructor taking a directory listing line and path
/// </summary>
/// <param name="line">The line returned from the detailed directory list</param>
/// <param name="path">Path of the directory</param>
/// <remarks></remarks>
public FTPfileInfo(string line, string path)
{
//parse line
Match m = GetMatchingRegex(line);
if (m == null)
{
//failed
throw (new ApplicationException("Unable to parse line: " + line));
}
else
{
_filename = m.Groups["name"].Value;
_path = path; Int64.TryParse(m.Groups["size"].Value, out _size);
//_size = System.Convert.ToInt32(m.Groups["size"].Value); _permission = m.Groups["permission"].Value;
string _dir = m.Groups["dir"].Value;
if (_dir != "" && _dir != "-")
{
_fileType = DirectoryEntryTypes.Directory;
}
else
{
_fileType = DirectoryEntryTypes.File;
} try
{
_fileDateTime = DateTime.Parse(m.Groups["timestamp"].Value);
}
catch (Exception)
{
_fileDateTime = Convert.ToDateTime(null);
} }
} private Match GetMatchingRegex(string line)
{
Regex rx;
Match m;
for (int i = 0; i <= _ParseFormats.Length - 1; i++)
{
rx = new Regex(_ParseFormats[i]);
m = rx.Match(line);
if (m.Success)
{
return m;
}
}
return null;
} #region "Regular expressions for parsing LIST results"
/// <summary>
/// List of REGEX formats for different FTP server listing formats
/// </summary>
/// <remarks>
/// The first three are various UNIX/LINUX formats, fourth is for MS FTP
/// in detailed mode and the last for MS FTP in 'DOS' mode.
/// I wish VB.NET had support for Const arrays like C# but there you go
/// </remarks>
private static string[] _ParseFormats = new string[] {
"(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\w+\\s+\\w+\\s+(?<size>\\d+)\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{4})\\s+(?<name>.+)",
"(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\d+\\s+(?<size>\\d+)\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{4})\\s+(?<name>.+)",
"(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\d+\\s+(?<size>\\d+)\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{1,2}:\\d{2})\\s+(?<name>.+)",
"(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\w+\\s+\\w+\\s+(?<size>\\d+)\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{1,2}:\\d{2})\\s+(?<name>.+)",
"(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})(\\s+)(?<size>(\\d+))(\\s+)(?<ctbit>(\\w+\\s\\w+))(\\s+)(?<size2>(\\d+))\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{2}:\\d{2})\\s+(?<name>.+)",
"(?<timestamp>\\d{2}\\-\\d{2}\\-\\d{2}\\s+\\d{2}:\\d{2}[Aa|Pp][mM])\\s+(?<dir>\\<\\w+\\>){0,1}(?<size>\\d+){0,1}\\s+(?<name>.+)" };
#endregion
}
#endregion #region "FTP Directory class"
/// <summary>
/// Stores a list of files and directories from an FTP result
/// </summary>
/// <remarks></remarks>
public class FTPdirectory : List<FTPfileInfo>
{ public FTPdirectory()
{
//creates a blank directory listing
} /// <summary>
/// Constructor: create list from a (detailed) directory string
/// </summary>
/// <param name="dir">directory listing string</param>
/// <param name="path"></param>
/// <remarks></remarks>
public FTPdirectory(string dir, string path)
{
foreach (string line in dir.Replace("\n", "").Split(System.Convert.ToChar('\r')))
{
//parse
if (line != "")
{
this.Add(new FTPfileInfo(line, path));
}
}
} /// <summary>
/// Filter out only files from directory listing
/// </summary>
/// <param name="ext">optional file extension filter</param>
/// <returns>FTPdirectory listing</returns>
public FTPdirectory GetFiles(string ext)
{
return this.GetFileOrDir(FTPfileInfo.DirectoryEntryTypes.File, ext);
} /// <summary>
/// Returns a list of only subdirectories
/// </summary>
/// <returns>FTPDirectory list</returns>
/// <remarks></remarks>
public FTPdirectory GetDirectories()
{
return this.GetFileOrDir(FTPfileInfo.DirectoryEntryTypes.Directory, "");
} //internal: share use function for GetDirectories/Files
private FTPdirectory GetFileOrDir(FTPfileInfo.DirectoryEntryTypes type, string ext)
{
FTPdirectory result = new FTPdirectory();
foreach (FTPfileInfo fi in this)
{
if (fi.FileType == type)
{
if (ext == "")
{
result.Add(fi);
}
else if (ext == fi.Extension)
{
result.Add(fi);
}
}
}
return result; } public bool FileExists(string filename)
{
foreach (FTPfileInfo ftpfile in this)
{
if (ftpfile.Filename == filename)
{
return true;
}
}
return false;
} private const char slash = '/'; public static string GetParentDirectory(string dir)
{
string tmp = dir.TrimEnd(slash);
int i = tmp.LastIndexOf(slash);
if (i > 0)
{
return tmp.Substring(0, i - 1);
}
else
{
throw (new ApplicationException("No parent for root"));
}
}
}
#endregion #region Events
public class DownloadProgressChangedArgs : EventArgs
{
//Private Members
private Int64 _BytesDownload;
private Int64 _TotalBytes; //Constructor
public DownloadProgressChangedArgs(Int64 BytesDownload, Int64 TotleBytes)
{
this._BytesDownload = BytesDownload;
this._TotalBytes = TotleBytes;
} //Public Members
public Int64 BytesDownloaded { get { return _BytesDownload; } }
public Int64 TotleBytes { get { return _TotalBytes; } }
} public class DownloadCompletedArgs : EventArgs
{
//Private Members
private bool _DownloadedCompleted;
private string _DownloadStatus; //Constructor
public DownloadCompletedArgs(string Status, bool Completed)
{
this._DownloadedCompleted = Completed;
this._DownloadStatus = Status;
} //Public Members
public String DownloadStatus { get { return _DownloadStatus; } }
public bool DownloadCompleted { get { return _DownloadedCompleted; } }
} public class NewMessageEventArgs : EventArgs
{
//Private Members
private string _Message;
private string _StatusCode;
private string _Type; //Constructor
public NewMessageEventArgs(string Type, string Status, string Code)
{
this._Message = Status;
this._StatusCode = Code;
this._Type = Type;
} //Public Members
public string StatusMessage { get { return _Message; } }
public string StatusCode { get { return _StatusCode; } }
public string StatusType { get { return _Type; } }
} public class UploadProgressChangedArgs : EventArgs
{
//Private Members
private Int64 _BytesUpload;
private Int64 _TotalBytes; //Constructor
public UploadProgressChangedArgs(Int64 BytesUpload, Int64 TotleBytes)
{
this._BytesUpload = BytesUpload;
this._TotalBytes = TotleBytes;
} //Public Members
public Int64 BytesUploaded { get { return _BytesUpload; } }
public Int64 TotleBytes { get { return _TotalBytes; } }
} public class UploadCompletedArgs : EventArgs
{
//Private Members
private bool _UploadCompleted;
private string _UploadStatus; //Constructor
public UploadCompletedArgs(string Status, bool Completed)
{
this._UploadCompleted = Completed;
this._UploadStatus = Status;
} //Public Members
public String UploadStatus { get { return _UploadStatus; } }
public bool UploadCompleted { get { return _UploadCompleted; } }
}
#endregion
}
测试代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using FTPLibrary;
using System.Diagnostics;
using System.Reflection;
using System.IO; namespace ftpdemo
{ /// <summary>
/// 涂聚文 2017-08-01
/// </summary>
public partial class Form6 : Form
{
public FTPclient FtpClient;
ListViewItem Message;
string remotingFolder = System.Configuration.ConfigurationManager.AppSettings["remotingFolder"]; //远程ftp文件目录
string localFolder = System.Configuration.ConfigurationManager.AppSettings["localFolder"]; //要下载到的本地目录
string ftpServer = System.Configuration.ConfigurationManager.AppSettings["ftpServer"]; //ftp服务器
string user = System.Configuration.ConfigurationManager.AppSettings["user"]; //用户名
string pwd = System.Configuration.ConfigurationManager.AppSettings["pwd"]; //密码
string port = System.Configuration.ConfigurationManager.AppSettings["port"]; //端口 /// <summary>
///
/// </summary>
/// <param name="byteCount"></param>
/// <returns></returns>
private string GetFileSize(double byteCount)
{
string size = "0 Bytes";
if (byteCount >= 1073741824.0)
size = String.Format("{0:##.##}", byteCount / 1073741824.0) + " GB";
else if (byteCount >= 1048576.0)
size = String.Format("{0:##.##}", byteCount / 1048576.0) + " MB";
else if (byteCount >= 1024.0)
size = String.Format("{0:##.##}", byteCount / 1024.0) + " KB";
else if (byteCount > 0 && byteCount < 1024.0)
size = byteCount.ToString() + " Bytes"; return size;
}
/// <summary>
/// Sets up the FTPClient for this Form. Called from frmLogin.
/// </summary>
/// <param name="client">FTPclient on frmLogin is used to refrence the FtpClient here.</param>
public void SetFtpClient(FTPclient client)
{
//Set FtpClient
FtpClient = client; //Display the Welcome Message
Message = new ListViewItem();
Message.Text = DateTime.Now.ToLongTimeString() + " " + DateTime.Now.ToLongDateString();
Message.SubItems.Add("Welcome Message");
Message.SubItems.Add(FtpClient.WelcomeMessage);
Message.SubItems.Add("No Code");
Message.SubItems.Add("/");
lstMessages.Items.Add(Message); //Setup OnMessageReceived Event
FtpClient.OnNewMessageReceived += new FTPclient.NewMessageHandler(FtpClient_OnNewMessageReceived); //Open and Display Root Directory and Files/Folders in it
foreach (FTPfileInfo folder in FtpClient.ListDirectoryDetail("/"))
{
ListViewItem item = new ListViewItem();
item.Text = folder.Filename;
if (folder.FileType == FTPfileInfo.DirectoryEntryTypes.Directory)
item.SubItems.Add("Folder");
else
item.SubItems.Add("File"); item.SubItems.Add(folder.FullName);
item.SubItems.Add(folder.Permission);
item.SubItems.Add(folder.FileDateTime.ToShortTimeString() + folder.FileDateTime.ToShortDateString());
item.SubItems.Add(GetFileSize(folder.Size));
lstRemoteSiteFiles.Items.Add(item);
}
}
/// <summary>
///
/// </summary>
/// <param name="myObject"></param>
/// <param name="e"></param>
private void FtpClient_OnNewMessageReceived(object myObject, NewMessageEventArgs e)
{
//Display Meesage in lstMessages
Message = new ListViewItem();
Message.Text = DateTime.Now.ToLongTimeString() + " " + DateTime.Now.ToLongDateString();
Message.SubItems.Add(e.StatusType);
Message.SubItems.Add(e.StatusMessage);
Message.SubItems.Add(e.StatusCode);
Message.SubItems.Add(txtRemoteDirectory.Text);
lstMessages.Items.Add(Message); this.lstMessages.EnsureVisible(this.lstMessages.Items.Count - 1);
}
/// <summary>
/// Reload all Directories and Files in Current Directory
/// </summary>
private void RefreshDirectory()
{
//Clear all items
lstRemoteSiteFiles.Items.Clear(); //Open and Display Root Directory
foreach (FTPfileInfo folder in FtpClient.ListDirectoryDetail(txtRemoteDirectory.Text))
{
ListViewItem item = new ListViewItem();
item.Text = folder.Filename;
if (folder.FileType == FTPfileInfo.DirectoryEntryTypes.Directory)
item.SubItems.Add("Folder");
else
item.SubItems.Add("File"); item.SubItems.Add(folder.FullName);
item.SubItems.Add(folder.Permission);
item.SubItems.Add(folder.FileDateTime.ToShortTimeString() + folder.FileDateTime.ToShortDateString());
item.SubItems.Add(folder.Size.ToString());
lstRemoteSiteFiles.Items.Add(item);
}
}
/// <summary>
///
/// </summary>
public Form6()
{
InitializeComponent(); //Set Selected Directory
txtRemoteDirectory.Text = "/";
lstRemoteSiteFiles.FullRowSelect = true;
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form6_Load(object sender, EventArgs e)
{
//Set FTP
FTPclient objFtp = new FTPclient(ftpServer, user,pwd);
objFtp.CurrentDirectory = "/";
SetFtpClient(objFtp); }
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void lstRemoteSiteFiles_SelectedIndexChanged(object sender, EventArgs e)
{ }
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void lstRemoteSiteFiles_MouseDoubleClick(object sender, MouseEventArgs e)
{
if (lstRemoteSiteFiles.Items.Count != 0)
{
try
{
if (lstRemoteSiteFiles.SelectedItems[0].SubItems[1].Text == "File")
{
//Enable the buttons that are related to the FILE
// btnRename.Enabled = true;
// btnDownload.Enabled = true;
//Set Current Directory for Download
FtpClient.CurrentDirectory = txtRemoteDirectory.Text;
//Its a File, so Ask them if they want to Save it...
if (MessageBox.Show("Do you want to save this file: " + txtRemoteDirectory.Text + lstRemoteSiteFiles.SelectedItems[0].Text + "/" + "?", "Download File?", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) == DialogResult.Yes)
{
//Save the File to location
//downloadToolStripMenuItem_Click(this, e);
}
}
else if (lstRemoteSiteFiles.SelectedItems[0].SubItems[1].Text == "Folder") // Its a Directory
{
//Set Directory to txtRemoteDirectory.Text + selectedItem + "/"
//Result - /SelectedDirecotory/ -- good for navigation, keeping user informed and code :)
txtRemoteDirectory.Text += lstRemoteSiteFiles.SelectedItems[0].Text + "/";
lstRemoteSiteFiles.Items.Clear(); //Set Current Dir
FtpClient.CurrentDirectory = txtRemoteDirectory.Text; //Get Files and Folders from Selected Direcotry
foreach (FTPfileInfo folder in FtpClient.ListDirectoryDetail(txtRemoteDirectory.Text))
{
ListViewItem item = new ListViewItem();
item.Text = folder.Filename;
if (folder.FileType == FTPfileInfo.DirectoryEntryTypes.Directory)
item.SubItems.Add("Folder");
else
item.SubItems.Add("File"); item.SubItems.Add(folder.FullName);
item.SubItems.Add(folder.Permission);
item.SubItems.Add(folder.FileDateTime.ToShortDateString()+" "+folder.FileDateTime.ToShortTimeString());
item.SubItems.Add(GetFileSize(folder.Size));
lstRemoteSiteFiles.Items.Add(item);
}
}
}
catch { }
}
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void lstRemoteSiteFiles_ItemDrag(object sender, ItemDragEventArgs e)
{ }
}
}
csharp: FTP Client Library using System.Net.FtpWebRequest的更多相关文章
- csharp: FTP Client Library using System.Net.FtpClient and FluentFTP,测试中存在的BUG修正
https://netftp.codeplex.com/ /// <summary> /// Gets a file listing from the server. Each FtpLi ...
- csharp:FTP Client Library using FtpWebRequest or Sockets
https://netftp.codeplex.com/SourceControl/latest http://ftplib.codeplex.com/ https://www.codeproject ...
- C# Ftp Client 基本操作
C# Ftp Client 上传.下载与删除 简单介绍一下Ftp Client 上传.下载与删除,这是目前比较常用的命令,各个方法其实都差不多,重点是了解Ftp命令协议. 1.建立连接 public ...
- Memcached通用类(基于Memcached Client Library)
分享下自己编写的Memcached通用类.欢迎大家帮忙指点下哈~ 使用的是.NET memcached client library 客户端+Memcached Providers using Sys ...
- 分布式缓存系统Memcached简介与实践(.NET memcached client library)
缘起: 在数据驱动的web开发中,经常要重复从数据库中取出相同的数据,这种重复极大的增加了数据库负载.缓存是解决这个问题的好办法.但是ASP.NET中的虽然已经可以实现对页面局部进行缓存,但还是不够灵 ...
- Intro to Jedis – the Java Redis Client Library
转自:http://www.baeldung.com/jedis-java-redis-client-library 1. Overview This article is an introducti ...
- System.Net.FtpWebRequest.cs
ylbtech-System.Net.FtpWebRequest.cs 实现文件传输协议(FTP)客户端. 1.返回顶部 1. #region 程序集 System, Version=4.0.0.0, ...
- Ubuntu Filezilla FTP Client 安装
/************************************************************************************* * Ubuntu File ...
- 谷歌正式发布Google APIs Client Library for .NET
好消息,特大好消息! 英文原文:Google API library for .NET paves the way for Google services on Windows phone 本月 17 ...
随机推荐
- Mac 下 软件安装路径查看 命令: Which, 估计Linux 也是
✘ marikobayashi@juk ~ which git /usr/bin/git marikobayashi@juk ~ which maven maven not found ...
- Thinking in Java from Chapter 10
From Thinking in Java 4th Edition 内部类 public class Parcel1 { class Contents { private int i = 11; pu ...
- PHP中url相关函数
1,string urlencode(string $str)/string urldecode(string $str) urlencode将中文以及特殊字符转化为16进制,然后在每个字符前面加%: ...
- 常用 Linux 命令使用说明
Linux 如果不知道某个命令的意思,通过 "man 命令" 可以查看它的使用方式及详细信息. 操作tomcat用到的相关命令 1.Enter 执行命令 2.Tab 自动补全命令 ...
- 我自己的sublime3环境
概述 我本来一直用的别人自带的破解版sublime3,自带插件. 前几天看<程序员修炼之道>,其中谈到了最好精通一种编辑器,我觉得说的很有道理,于是重新下了最新版的sublime3,一步步 ...
- shell if 条件判断
condition='123' if [ -z condition]; then echo "condition 是空的" fi 字符串判断: = 两个字符串相等. != 两个字符 ...
- mysql之select语法
一:连接查询(外链接outer和内链接inner) 连接查询是另一种类型的多表查询.连接查询对多个表进行JOIN运算,简单地说,就是先确定一个主表作为结果集,然后,把其他表的行有选择性地“连接”在主表 ...
- 3-2 模板语法(vue中的内容写法)
插值表达式.v-text.v-html的用法
- git 服务器搭建及提交代码检查
本地 git 服务,通常都会选择 gitlab.本人最先也是选择 gitlab,在 centos7 上按照官网的步骤进行安装,下载的速度难以忍受,无奈放弃.最终选择在 docker 中安装 gogs ...
- 比较List和ArrayList的性能及ArrayList和LinkedList优缺点
List和ArrayList的性能比较 在使用ArrayList这样的非泛型集合的过程中,要进行装箱和拆箱操作,会有比较大的性能损失,而使用泛型集合就没有这样的问题.List是泛型,而ArrayLis ...