Files
ATV_STDLabelAttach/Handler/Project/Class/FTP/FTPClient.cs
2025-07-17 16:11:46 +09:00

575 lines
17 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
namespace AR.FTPClient
{
public partial class FTPClient : IFTPClient
{
public string errorMessage { get; set; }
private int bufferSize = 2048;
private int timeout = 20000;
#region "Contstruct"
public FTPClient() : this("127.0.0.1", "Anonymous", "") { }
public FTPClient(string Host, string UserID, string UserPass) :
this(Host, UserID, UserPass, 21)
{ }
public FTPClient(string Host, string UserID, string UserPass, bool passive) :
this(Host, UserID, UserPass, 21, passive)
{ }
public FTPClient(string Host, string UserID, string UserPass, int port) :
this(Host, UserID, UserPass, port, false)
{ }
public FTPClient(string host, string userid, string userpass, int port, bool passive)
{
Host = host;
UserID = userid;
UserPassword = userpass;
Port = port;
PassiveMode = passive;
this.TextEncoding = System.Text.Encoding.UTF8;
}
#endregion
public event EventHandler<MessageEventArgs> Message;
public event EventHandler<ListProgressEventArgs> ListPrgress;
#region "Properties"
/// <summary>
/// 접속하려는 FTP서버의 IP혹은 도메인 주소를 입력하세요
/// 기본값 : 127.0.0.1
/// </summary>
public string Host { get; set; }
/// <summary>
/// FTP의 사용자 ID
/// 기본값 : Anonymous
/// </summary>
public string UserID { get; set; }
/// <summary>
/// FTP 사용자 ID의 암호
/// 기본값 : 없음
/// </summary>
public string UserPassword { get; set; }
/// <summary>
/// FTP 접속 포트
/// 기본값 : 21
/// </summary>
public int Port { get; set; }
/// <summary>
/// FTP 접속 방식 (능동형/수동형)
/// </summary>
public bool PassiveMode { get; set; }
/// <summary>
/// 문자수신시 사용할 인코딩 방식
/// </summary>
public System.Text.Encoding TextEncoding { get; set; }
#endregion
public void Dispose()
{
}
/// <summary>
/// 파일을 다운로드 합니다.
/// </summary>
/// <param name="remoteFile">원격위치의 전체 경로</param>
/// <param name="localFile">로컬위치의 전체 경로</param>
public Boolean Download(string remoteFile, string localFile, bool overwrite = false)
{
FtpWebRequest ftpRequest = null;
FtpWebResponse ftpResponse = null;
Stream ftpStream = null;
//overwrite funcion - 190622 - chi
errorMessage = string.Empty;
if (overwrite == false && System.IO.File.Exists(localFile))
{
errorMessage = "Target file alreay exists";
return false;
}
else if (overwrite == true && System.IO.File.Exists(localFile))
{
try
{
System.IO.File.Delete(localFile);
}
catch (Exception ex)
{
errorMessage = ex.Message;
return false;
}
}
bool retval = true;
try
{
long Receive = 0;
var url = CombineUrl(remoteFile);
ftpRequest = (FtpWebRequest)FtpWebRequest.Create(url);
ftpRequest.Credentials = new NetworkCredential(this.UserID, this.UserPassword);
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = this.PassiveMode;
ftpRequest.KeepAlive = true;
ftpRequest.ReadWriteTimeout = this.timeout;
ftpRequest.Method = WebRequestMethods.Ftp.DownloadFile;
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
ftpStream = ftpResponse.GetResponseStream();
FileStream localFileStream = new FileStream(localFile, FileMode.Create);
byte[] byteBuffer = new byte[bufferSize];
int bytesRead = ftpStream.Read(byteBuffer, 0, bufferSize);
Receive += bytesRead;
if (ListPrgress != null)
ListPrgress(this, new ListProgressEventArgs(Receive));
try
{
while (bytesRead > 0)
{
localFileStream.Write(byteBuffer, 0, bytesRead);
bytesRead = ftpStream.Read(byteBuffer, 0, bufferSize);
Receive += bytesRead;
if (ListPrgress != null)
ListPrgress(this, new ListProgressEventArgs(Receive));
}
}
catch (Exception ex) { retval = false; Console.WriteLine(ex.ToString()); }
localFileStream.Close();
ftpStream.Close();
ftpResponse.Close();
ftpRequest = null;
}
catch (Exception ex) { retval = false; this.errorMessage = ex.Message; Console.WriteLine(ex.ToString()); }
return retval;
}
/// <summary>
/// 파일을 업로드 합니다.
/// </summary>
/// <param name="remoteFile">원격위치의 전체 경로</param>
/// <param name="localFile">로컬위치의 전체 경로</param>
/// <returns></returns>
public Boolean Upload(string remoteFile, string localFile)
{
FtpWebRequest ftpRequest = null;
FtpWebResponse ftpResponse = null;
Stream ftpStream = null;
try
{
var url = CombineUrl(remoteFile);
ftpRequest = (FtpWebRequest)FtpWebRequest.Create(url);
ftpRequest.Credentials = new NetworkCredential(UserID, UserPassword);
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = PassiveMode;
ftpRequest.KeepAlive = true;
ftpRequest.ReadWriteTimeout = this.timeout;
ftpRequest.Method = WebRequestMethods.Ftp.UploadFile;
ftpStream = ftpRequest.GetRequestStream();
FileStream localFileStream = new FileStream(localFile, FileMode.Open);
byte[] byteBuffer = new byte[bufferSize];
int bytesSent = localFileStream.Read(byteBuffer, 0, bufferSize);
Boolean bError = false;
try
{
System.Diagnostics.Stopwatch wat = new System.Diagnostics.Stopwatch();
wat.Restart();
while (bytesSent != 0)
{
ftpStream.Write(byteBuffer, 0, bytesSent);
bytesSent = localFileStream.Read(byteBuffer, 0, bufferSize);
}
}
catch (Exception ex)
{
bError = true;
}
localFileStream.Close();
ftpStream.Close();
ftpRequest = null;
if (bError) return false;
else return true;
}
catch (Exception ex)
{
this.errorMessage = ex.Message;
return false;
}
}
/// <summary>
/// 원격파일을 삭제 합니다.
/// </summary>
/// <param name="remotefile"></param>
public Boolean Delete(string remotefile)
{
FtpWebRequest ftpRequest = null;
FtpWebResponse ftpResponse = null;
Stream ftpStream = null;
try
{
var url = CombineUrl(remotefile);
ftpRequest = (FtpWebRequest)WebRequest.Create(url);
ftpRequest.Credentials = new NetworkCredential(UserID, UserPassword);
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = this.PassiveMode;
ftpRequest.KeepAlive = true;
ftpRequest.ReadWriteTimeout = this.timeout;
ftpRequest.Method = WebRequestMethods.Ftp.DeleteFile;
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
ftpResponse.Close();
ftpRequest = null;
return true;
}
catch (Exception ex) { this.errorMessage = ex.Message; return false; }
}
/// <summary>
/// 원격파일의 이름을 변경 합니다.
/// </summary>
/// <param name="currentFileNameAndPath"></param>
/// <param name="newFileName"></param>
public Boolean rename(string currentFileNameAndPath, string newFileName)
{
FtpWebRequest ftpRequest = null;
FtpWebResponse ftpResponse = null;
Stream ftpStream = null;
try
{
var url = CombineUrl(currentFileNameAndPath);
ftpRequest = (FtpWebRequest)WebRequest.Create(url);
ftpRequest.Credentials = new NetworkCredential(UserID, UserPassword);
ftpRequest.UsePassive = this.PassiveMode;
ftpRequest.ReadWriteTimeout = this.timeout;
ftpRequest.UseBinary = true;
ftpRequest.KeepAlive = true;
ftpRequest.Method = WebRequestMethods.Ftp.Rename;
ftpRequest.RenameTo = newFileName;
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
ftpResponse.Close();
ftpRequest = null;
return true;
}
catch (Exception ex) { this.errorMessage = ex.Message; return false; }
}
/// <summary>
/// 원격위치에 폴더를 생성 합니다.
/// 트리구조로 폴더를 생성하지 않습니다. 여러개의 폴더를 생성하려면 각각 호출 해야 합니다.
/// </summary>
/// <param name="newDirectory"></param>
/// <returns></returns>
public bool createDirectory(string newDirectory)
{
FtpWebRequest ftpRequest = null;
FtpWebResponse ftpResponse = null;
Stream ftpStream = null;
try
{
var url = CombineUrl(newDirectory, false);
ftpRequest = (FtpWebRequest)WebRequest.Create(url);
ftpRequest.Credentials = new NetworkCredential(UserID, UserPassword);
ftpRequest.UsePassive = this.PassiveMode;
ftpRequest.UseBinary = true;
ftpRequest.KeepAlive = true;
ftpRequest.ReadWriteTimeout = this.timeout;
ftpRequest.Method = WebRequestMethods.Ftp.MakeDirectory;
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
ftpResponse.Close();
ftpRequest = null;
return true;
}
catch (Exception ex) { this.errorMessage = ex.Message; return false; }
}
/// <summary>
/// 원격위치의 폴더를 삭제합니다. 폴더 삭제 전 대상 폴더는 비어있어야 합니다.
/// </summary>
/// <param name="Directory"></param>
/// <returns></returns>
public bool RemoveDirectory(string Directory)
{
FtpWebRequest ftpRequest = null;
FtpWebResponse ftpResponse = null;
Stream ftpStream = null;
try
{
var url = CombineUrl(Directory, false);
ftpRequest = (FtpWebRequest)WebRequest.Create(url);
ftpRequest.Credentials = new NetworkCredential(UserID, UserPassword);
ftpRequest.UsePassive = this.PassiveMode;
ftpRequest.UseBinary = true;
ftpRequest.KeepAlive = true;
ftpRequest.ReadWriteTimeout = this.timeout;
ftpRequest.Method = WebRequestMethods.Ftp.RemoveDirectory;
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
ftpResponse.Close();
ftpRequest = null;
return true;
}
catch (Exception ex) { this.errorMessage = ex.Message; return false; }
}
/// <summary>
/// 파일의 생성일자 반환
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public string getFileCreatedDateTime(string fileName)
{
FtpWebRequest ftpRequest = null;
FtpWebResponse ftpResponse = null;
Stream ftpStream = null;
try
{
var url = CombineUrl(fileName);
ftpRequest = (FtpWebRequest)WebRequest.Create(url);
ftpRequest.Credentials = new NetworkCredential(UserID, UserPassword);
ftpRequest.UsePassive = this.PassiveMode;
ftpRequest.UseBinary = true;
ftpRequest.KeepAlive = true;
ftpRequest.ReadWriteTimeout = this.timeout;
ftpRequest.Method = WebRequestMethods.Ftp.GetDateTimestamp;
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
ftpStream = ftpResponse.GetResponseStream();
StreamReader ftpReader = new StreamReader(ftpStream, this.TextEncoding);
string fileInfo = null;
try { fileInfo = ftpReader.ReadToEnd(); }
catch (Exception ex) { Console.WriteLine(ex.ToString()); }
ftpReader.Close();
ftpStream.Close();
ftpResponse.Close();
ftpRequest = null;
return fileInfo;
}
catch (Exception ex) { this.errorMessage = ex.Message; Console.WriteLine(ex.ToString()); }
return "";
}
/// <summary>
/// 파일의 크기를 반환
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public string getFileSize(string fileName)
{
FtpWebRequest ftpRequest = null;
FtpWebResponse ftpResponse = null;
Stream ftpStream = null;
try
{
var url = CombineUrl(fileName);
ftpRequest = (FtpWebRequest)WebRequest.Create(url);
ftpRequest.Credentials = new NetworkCredential(UserID, UserPassword);
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = this.PassiveMode;
ftpRequest.KeepAlive = true;
ftpRequest.ReadWriteTimeout = this.timeout;
ftpRequest.Method = WebRequestMethods.Ftp.GetFileSize;
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
ftpStream = ftpResponse.GetResponseStream();
StreamReader ftpReader = new StreamReader(ftpStream, this.TextEncoding);
string fileInfo = null;
try { while (ftpReader.Peek() != -1) { fileInfo = ftpReader.ReadToEnd(); } }
catch (Exception ex) { Console.WriteLine(ex.ToString()); }
ftpReader.Close();
ftpStream.Close();
ftpResponse.Close();
ftpRequest = null;
return fileInfo;
}
catch (Exception ex) { errorMessage = ex.Message; Console.WriteLine(ex.ToString()); }
return "";
}
/// <summary>
/// 폴더와 파일의 이름만 반환 합니다.
/// </summary>
/// <param name="directory"></param>
/// <returns></returns>
public string[] directoryListSimple(string directory)
{
FtpWebRequest ftpRequest = null;
FtpWebResponse ftpResponse = null;
Stream ftpStream = null;
errorMessage = string.Empty;
try
{
var url = CombineUrl(directory, false);
if (url.EndsWith("/") == false) url += "/";
ftpRequest = (FtpWebRequest)WebRequest.Create(url);
ftpRequest.Credentials = new NetworkCredential(UserID, UserPassword);
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = PassiveMode;
ftpRequest.KeepAlive = true;
ftpRequest.ReadWriteTimeout = this.timeout;
ftpRequest.ReadWriteTimeout = 30000;
ftpRequest.Timeout = 30000;
ftpRequest.Method = WebRequestMethods.Ftp.ListDirectory;
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
ftpStream = ftpResponse.GetResponseStream();
StreamReader ftpReader = new StreamReader(ftpStream, this.TextEncoding);
string directoryRaw = null;
try
{
while (ftpReader.Peek() != -1)
{
var dataLIne = ftpReader.ReadLine();
if (dataLIne.Trim() != "")
{
if (directoryRaw != null && directoryRaw != "") directoryRaw += "|";
directoryRaw += dataLIne;
}
}
}
catch (Exception ex) { errorMessage += "\n" + ex.Message; }
ftpReader.Close();
ftpStream.Close();
ftpResponse.Close();
ftpRequest = null;
try { string[] directoryList = directoryRaw.Split("|".ToCharArray()); return directoryList; }
catch (Exception ex) { errorMessage += "\n" + ex.Message; }
}
catch (Exception ex) { errorMessage = ex.Message; Console.WriteLine(ex.ToString()); }
return new string[] { "" };
}
/// <summary>
/// 폴더 및 파일의 정보를 상세하게 표시합니다.
/// </summary>
/// <param name="directory"></param>
/// <returns></returns>
public FTPdirectory ListDirectoryDetail(string directory)
{
FtpWebRequest ftpRequest = null;
FtpWebResponse ftpResponse = null;
Stream ftpStream = null;
errorMessage = string.Empty;
try
{
var url = CombineUrl(directory, false);
if (url.EndsWith("/") == false) url += "/";
ftpRequest = (FtpWebRequest)WebRequest.Create(url);
ftpRequest.Credentials = new NetworkCredential(UserID, UserPassword);
ftpRequest.UsePassive = true;
ftpRequest.UseBinary = true;
ftpRequest.KeepAlive = false;
ftpRequest.ReadWriteTimeout = this.timeout;
ftpRequest.ReadWriteTimeout = 30000;
ftpRequest.Timeout = 30000;
ftpRequest.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
ftpStream = ftpResponse.GetResponseStream();
StreamReader ftpReader = new StreamReader(ftpStream, this.TextEncoding);
string directoryRaw = null;
try { while (ftpReader.Peek() != -1) { directoryRaw += ftpReader.ReadLine() + "\r"; } }
catch (Exception ex) { errorMessage += "\n" + ex.Message; }
ftpReader.Close();
ftpStream.Close();
ftpResponse.Close();
ftpRequest = null;
directoryRaw = directoryRaw.Replace("\r\n", "\r").TrimEnd((char)0x0D);
return new FTPdirectory(directoryRaw, directory);
}
catch (Exception ex) { errorMessage += "\n" + ex.Message; }
return null;
}
#region "utillity"
/// <summary>
/// Url을 Host와 결합하여 생성
/// </summary>
/// <param name="file">경로명</param>
/// <param name="isfile">파일인지 여부</param>
/// <returns></returns>
string CombineUrl(string file, bool isfile = true)
{
file = file.Replace("\\", "/");
string url = this.Host;
if (this.Host.ToLower().StartsWith("ftp://") == false) url = "ftp://" + url;
if (url.Substring(5).LastIndexOf(':') == -1)
url += ":" + this.Port.ToString();
if (this.Host.EndsWith("/")) url = this.Host.Substring(0, Host.Length - 1);
if (file.StartsWith("/"))
url = url + System.Web.HttpUtility.UrlPathEncode(file);
else
url = url + "/" + System.Web.HttpUtility.UrlPathEncode(file);
url = url.Replace("#", "%23");
if (isfile)
return url;
else
return url + "/";
}
public string PathCombine(string path, string add)
{
var newpath = string.Empty;
if (path.EndsWith("/")) newpath = path + add;
else newpath = path + "/" + add;
if (!newpath.EndsWith("/")) newpath += '/';
return newpath;
}
public string PathFileCombine(string path, string add)
{
var newpath = string.Empty;
if (path.EndsWith("/")) newpath = path + add;
else newpath = path + "/" + add;
if (newpath.EndsWith("/")) newpath = newpath.Substring(0, newpath.Length - 1);
return newpath;
}
public string getParent(string path)
{
if (path == "/") return path;
else if (path == "") return "/";
else
{
//서브폴더를 찾아서 처리해준다.
if (path.IndexOf('/') == -1) return "/";
else
{
if (path.EndsWith("/")) path = path.Substring(0, path.Length - 1);
var slashindex = path.LastIndexOf('/');
var parent = path.Substring(0, slashindex);
if (!parent.EndsWith("/")) parent += '/';
return parent;
}
}
}
public void RaiseMessage(Boolean isError, string message)
{
if (isError) errorMessage = message; //170920
if (Message != null) Message(this, new MessageEventArgs(isError, message));
}
#endregion
}
}