using System.Diagnostics; using System.Data; using System.Collections; using Microsoft.VisualBasic; using System.Collections.Generic; using System; using System.Net; using System.IO; using System.Text.RegularExpressions; using System.Globalization; namespace FTPClients { #region "FTP client class" /// /// A wrapper class for .NET 2.0 FTP /// /// /// This class does not hold open an FTP connection but /// instead is stateless: for each FTP request it /// connects, performs the request and disconnects. /// public class Client_2 { ////프로브센서의 제목이 클릭됨 // public event MessageHandler Message; public delegate void MessageHandler(int idx); #region "CONSTRUCTORS" /// /// Blank constructor /// /// Hostname, username and password must be set manually public Client_2() { utf8 = false; Passive = true; } /// /// Constructor just taking the hostname /// /// in either ftp://ftp.host.com or ftp.host.com form /// public Client_2(string Hostname) { _hostname = Hostname; utf8 = false; Passive = true; } /// /// Constructor taking hostname, username and password /// /// in either ftp://ftp.host.com or ftp.host.com form /// Leave blank to use 'anonymous' but set password to your email /// /// public Client_2(string Hostname, string Username, string Password) { _hostname = Hostname; _username = Username; _password = Password; utf8 = false; Passive = true; } #endregion #region "Directory functions" /// /// Return a simple directory listing /// /// Directory to list, e.g. /pub /// A list of filenames and directories as a List(of String) /// For a detailed directory listing, use ListDirectoryDetail public List 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; 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 result = new List(); result.AddRange(str.Split('\r')); return result; } /// /// Return a detailed directory listing /// /// Directory to list, e.g. /pub/etc /// An FTPDirectory object 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; 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); } public void Close() { System.Net.FtpWebRequest ftp = GetRequest(GetDirectory("/")); ftp.Abort(); } #endregion #region "Upload: File transfer TO ftp server" /// /// Copy a local file to the FTP server /// /// Full path of the local file /// Target filename, if required /// /// 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. 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); } /// /// Upload a local file to the FTP server /// /// Source file /// Target filename (optional) /// 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 = host + target; //perform copy System.Net.FtpWebRequest ftp = GetRequest(URI); //Set request to upload a file in binary ftp.Method = System.Net.WebRequestMethods.Ftp.UploadFile; ftp.UseBinary = true; //Notify FTP of the expected size ftp.ContentLength = fi.Length; //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 (FileStream fs = fi.OpenRead()) { try { //open request to send using (Stream rs = ftp.GetRequestStream()) { do { dataRead = fs.Read(content, 0, BufferSize); rs.Write(content, 0, dataRead); } while (!(dataRead < BufferSize)); rs.Close(); } } catch (Exception) { } finally { //ensure file closed fs.Close(); } } ftp = null; return true; } #endregion #region "Download: File transfer FROM ftp server" /// /// Copy a file from FTP server to local /// /// Target filename, if required /// Full path of the local file /// /// Target can be blank (use same filename), or just a filename /// (assumes current directory) or a full path and filename 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); } //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 = host + target; //3. perform copy System.Net.FtpWebRequest ftp = GetRequest(URI); //Set request to download a file in binary mode ftp.Method = System.Net.WebRequestMethods.Ftp.DownloadFile; ftp.UseBinary = true; //open request and get response stream using (FtpWebResponse response = (FtpWebResponse)ftp.GetResponse()) { using (Stream responseStream = response.GetResponseStream()) { //loop to read & write to file using (FileStream fs = targetFI.OpenWrite()) { try { byte[] buffer = new byte[2048]; int read = 0; do { read = responseStream.Read(buffer, 0, buffer.Length); fs.Write(buffer, 0, read); } while (!(read == 0)); responseStream.Close(); fs.Flush(); fs.Close(); } catch (Exception) { //catch error and delete file only partially downloaded fs.Close(); //delete target file as it's incomplete targetFI.Delete(); throw; } } responseStream.Close(); } response.Close(); } return true; } #endregion #region "Other functions: Delete rename etc." /// /// Delete remote file /// /// filename or full path /// /// public bool FtpDelete(string filename) { //Determine if file or full path string URI = this.host + 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); } catch (Exception) { return false; } return true; } /// /// Determine if file exists on remote FTP site /// /// Filename (for current dir) or full path /// /// Note this only works for files 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 { throw; } } else { throw; } } } /// /// Determine size of remote file /// /// /// /// Throws an exception if file does not exist public long GetFileSize(string filename) { string path; if (filename.Contains("/")) { path = AdjustDir(filename); } else { path = this.CurrentDirectory + filename; } string URI = this.host + 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); 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.host + source; System.Net.FtpWebRequest ftp = GetRequest(URI); //Set request to delete ftp.Method = System.Net.WebRequestMethods.Ftp.Rename; ftp.RenameTo = target; try { //get response but ignore it string str = GetStringResponse(ftp); } catch (Exception) { return false; } return true; } public bool FtpCreateDirectory(string dirpath) { //perform create string URI = this.host + 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); } catch (Exception) { return false; } return true; } public bool FtpDeleteDirectory(string dirpath) { //perform remove string URI = this.host + AdjustDir(dirpath); System.Net.FtpWebRequest ftp = GetRequest(URI); //Set request to RmDir ftp.Method = System.Net.WebRequestMethods.Ftp.RemoveDirectory; try { //get response but ignore it string str = GetStringResponse(ftp); } 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 = true; result.UsePassive = this.Passive; return result; } /// /// Get the credentials from username/password /// private System.Net.ICredentials GetCredentials() { return new System.Net.NetworkCredential(user, pass); } /// /// returns a full path using CurrentDirectory for a relative file reference /// private string GetFullPath(string file) { if (file.Contains("/")) { return AdjustDir(file); } else { return this.CurrentDirectory + file; } } /// /// Amend an FTP path so that it always starts with / /// /// Path to adjust /// /// private string AdjustDir(string path) { return ((path.StartsWith("/")) ? "" : "/").ToString() + path; } private string GetDirectory(string directory) { string URI; if (directory == "") { //build from current URI = host + this.CurrentDirectory; _lastDirectory = this.CurrentDirectory; } else { if (!directory.StartsWith("/")) { throw (new ApplicationException("Directory should start with /")); } URI = this.host + directory; _lastDirectory = directory; } return URI; } //stores last retrieved/set directory private string _lastDirectory = ""; /// /// Obtains a response stream as a string /// /// current FTP request /// String containing response /// FTP servers typically return strings with CR and /// not CRLF. Use respons.Replace(vbCR, vbCRLF) to convert /// to an MSDOS string 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()) { if(utf8) { using (StreamReader sr = new StreamReader(datastream,System.Text.Encoding.UTF8)) { result = sr.ReadToEnd(); sr.Close(); } } else { using (StreamReader sr = new StreamReader(datastream,System.Text.Encoding.Default)) { result = sr.ReadToEnd(); sr.Close(); } } datastream.Close(); } response.Close(); } return result; } /// /// Gets the size of an FTP request /// /// /// /// 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; public Boolean Passive { get; set; } public Boolean utf8 { get; set; } /// /// Hostname /// /// /// Hostname can be in either the full URL format /// ftp://ftp.myhost.com or just ftp.myhost.com /// public string host { get { if (_hostname.StartsWith("ftp://")) { return _hostname; } else { return "ftp://" + _hostname; } } set { _hostname = value; } } private string _username; /// /// Username property /// /// /// Can be left blank, in which case 'anonymous' is returned public string user { get { return (_username == "" ? "anonymous" : _username); } set { _username = value; } } private string _password; public string pass { get { return _password; } set { _password = value; } } /// /// The CurrentDirectory value /// /// Defaults to the root '/' 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 } #endregion #region "FTP file info class" /// /// Represents a file or directory entry from an FTP listing /// /// /// This class is used to parse the results from a detailed /// directory list from FTP. It supports most formats of /// 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 /// /// Identifies entry as either File or Directory /// public enum DirectoryEntryTypes { File, Directory } /// /// Constructor taking a directory listing line and path /// /// The line returned from the detailed directory list /// Path of the directory /// 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; } string sdatetime = m.Groups["timestamp"].Value; DateTime dt = Convert.ToDateTime(null); if (!DateTime.TryParse(sdatetime, out dt)) { if (!DateTime.TryParse(sdatetime, CultureInfo.CreateSpecificCulture("en-US"), DateTimeStyles.None, out dt)) { if (!DateTime.TryParse(sdatetime, CultureInfo.CreateSpecificCulture("fr-FR"), DateTimeStyles.None, out dt)) { if (!DateTime.TryParse(sdatetime, CultureInfo.CreateSpecificCulture("de-DE"), DateTimeStyles.None, out dt)) { } } } } _fileDateTime = dt; ////날짜해석부분 추가 160715 //CultureInfo[] cultures = {CultureInfo.CreateSpecificCulture("en-US"), // CultureInfo.CreateSpecificCulture("fr-FR"), // CultureInfo.CreateSpecificCulture("de-DE")}; //foreach (CultureInfo culture in cultures) //{ // string dt = "07-13-16 10:39PM"; // try // { // DateTime dtv = DateTime.Parse(dt, culture); // MessageBox.Show(dtv.ToString()); // } // catch (Exception ex) // { // MessageBox.Show(ex.Message); // } //} //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" /// /// List of REGEX formats for different FTP server listing formats /// /// /// 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 /// private static string[] _ParseFormats = new string[] { "(?[\\-d])(?([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\w+\\s+\\w+\\s+(?\\d+)\\s+(?\\w+\\s+\\d+\\s+\\d{4})\\s+(?.+)", "(?[\\-d])(?([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\d+\\s+(?\\d+)\\s+(?\\w+\\s+\\d+\\s+\\d{4})\\s+(?.+)", "(?[\\-d])(?([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\d+\\s+(?\\d+)\\s+(?\\w+\\s+\\d+\\s+\\d{1,2}:\\d{2})\\s+(?.+)", "(?[\\-d])(?([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\w+\\s+\\w+\\s+(?\\d+)\\s+(?\\w+\\s+\\d+\\s+\\d{1,2}:\\d{2})\\s+(?.+)", "(?[\\-d])(?([\\-r][\\-w][\\-xs]){3})(\\s+)(?(\\d+))(\\s+)(?(\\w+\\s\\w+))(\\s+)(?(\\d+))\\s+(?\\w+\\s+\\d+\\s+\\d{2}:\\d{2})\\s+(?.+)", "(?\\d{2}\\-\\d{2}\\-\\d{2}\\s+\\d{2}:\\d{2}[Aa|Pp][mM])\\s+(?\\<\\w+\\>){0,1}(?\\d+){0,1}\\s+(?.+)" }; #endregion } #endregion #region "FTP Directory class" /// /// Stores a list of files and directories from an FTP result /// /// public class FTPdirectory : List { public FTPdirectory() { //creates a blank directory listing } /// /// Constructor: create list from a (detailed) directory string /// /// directory listing string /// /// 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)); } } } /// /// Filter out only files from directory listing /// /// optional file extension filter /// FTPdirectory listing public FTPdirectory GetFiles(string ext) { return this.GetFileOrDir(FTPfileInfo.DirectoryEntryTypes.File, ext); } /// /// Returns a list of only subdirectories /// /// FTPDirectory list /// 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 (string.IsNullOrEmpty(ext)) { result.Add(fi); } else if (ext.ToLower() == fi.Extension.ToLower()) { 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 }