using System;using System.Collections.Generic;using System.Linq;using System.Net;using System.Text;using System.IO;namespace FtpUtil
{/// <summary>/// Connect to a FTP server to list, transfer, delete and rename files/// </summary>publicclassFTPHelper{publicstring Server {get;set;}publicstring User {get;set;}publicstring Password {get;set;}publicstring RootFolder {get;set;}publicFtpStatusCode LastStatusCode {get;set;}publicstring LastStatusDescription {get;set;}publicstring LastErrorMessage {get;set;}privatestring _workingFolder ="";privatestring _lastWorkingFolderListed =null;privatebool _fileInfoListDirty =true;privatebool getFileTimeStampNotSupported =false;private List<myFTPFileInfo> _fileInfoList =newList<myFTPFileInfo>();publicFTPHelper(string server,string user,string password,string folder){
Server = server;
User = user;
Password = password;
RootFolder = folder.Trim();if(RootFolder ==null){
RootFolder ="";};if(RootFolder.Length >0&&!RootFolder.StartsWith("/")){
RootFolder ="/"+ RootFolder;};if(RootFolder.EndsWith("/")){
RootFolder = RootFolder.Substring(0, RootFolder.Length -1);}}/// <summary>/// 遍历获取文件名/// Obtains a simple file list with the filenames on the FTP server using a wildcard starting at the current remote FTP folder/// </summary>/// <param name="fileSpec">A wildcard to specify the filenames to be searched for and listed. Example: "subfolder/*.txt"</param>/// <returns>A list with the filenames found</returns>public List<string>GetFileList(string fileSpec){if(fileSpec ==null) fileSpec ="";if(fileSpec.Length >0&&!fileSpec.StartsWith("/")){
fileSpec ="/"+ fileSpec;}var ret =newList<string>();var req =(FtpWebRequest)WebRequest.Create("ftp://"+ Server + RootFolder + _workingFolder + fileSpec);
req.Proxy =null;
req.EnableSsl =false;
req.Credentials =newNetworkCredential(User, Password);
req.Method = WebRequestMethods.Ftp.ListDirectory;using(WebResponse resp = req.GetResponse()){using(StreamReader reader =newStreamReader(resp.GetResponseStream())){while(!reader.EndOfStream){
ret.Add(reader.ReadLine());};};RecordResponseStatus((FtpWebResponse)resp);}return ret;}/// <summary>/// 获取多个文件详细信息/// Obtains a detailed list of the filenames in the current remote FTP folder/// </summary>/// <returns>A detailed list of files found</returns>public List<myFTPFileInfo>GetFileListDetailed(){returnGetFileListDetailed("",false);}/// <summary>/// 获取单个文件详细信息/// Obtains a detailed list of the files in the current remote FTP folder according to a wildcard filename specification/// </summary>/// <param name="fileSpec">Wildcard filename specification. Can contain subfolders and *'s. Example: subfolder/*.txt</param>/// <returns>A detailed list of files found</returns>/// <remarks>If wildcard is specified the resulting file list is not cached</remarks>public List<myFTPFileInfo>GetFileListDetailed(string fileSpec){returnGetFileListDetailed(fileSpec,false);}/// <summary>/// Obtains a detailed list of the files in the current remote FTP folder according to a wildcard filename specification and allows to bypass the cached filelist/// </summary>/// <param name="fileSpec">Wildcard filename specification. Can contain subfolders and *'s. Example: subfolder/*.txt</param>/// <param name="forceRefresh">If true the cache is ignored</param>/// <returns></returns>/// <remarks>If wildcard is specified or forceRefresh is set to true the resulting file list is not cached</remarks>public List<myFTPFileInfo>GetFileListDetailed(string fileSpec,bool forceRefresh){if(fileSpec ==null|| fileSpec.Trim().Length ==0){
fileSpec ="*";}if(fileSpec.Length >0&&!fileSpec.StartsWith("/")){
fileSpec ="/"+ fileSpec;}
List<myFTPFileInfo> fileList =newList<myFTPFileInfo>();if(forceRefresh ||
fileSpec.Trim().Length >0||
_fileInfoListDirty ||
_lastWorkingFolderListed != _workingFolder){var req =(FtpWebRequest)WebRequest.Create("ftp://"+ Server + RootFolder + _workingFolder + fileSpec);
req.Proxy =null;
req.EnableSsl =false;
req.Credentials =newNetworkCredential(User, Password);
req.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
myFTPFileInfo ftpFileInfo;
_fileInfoList.Clear();try{using(FtpWebResponse resp =(FtpWebResponse)req.GetResponse()){using(StreamReader reader =newStreamReader(resp.GetResponseStream())){while(!reader.EndOfStream){
ftpFileInfo =newmyFTPFileInfo(reader.ReadLine());if(ftpFileInfo.Nombre !=null&& ftpFileInfo.Nombre.Trim().Length >0){
fileList.Add(ftpFileInfo);}};};RecordResponseStatus(resp);};}catch(System.Net.WebException ex){if(((FtpWebResponse)ex.Response).StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable){RecordResponseStatus((FtpWebResponse)ex.Response);}else{throw ex;}}if(fileSpec.Trim().Length ==0|| fileSpec.Trim()=="/*"){//Solo conserva cache de la lista de archivos cuando se solicita sin comodines
_fileInfoList = fileList;
_lastWorkingFolderListed = _workingFolder;
_fileInfoListDirty =false;}return fileList;}else{return _fileInfoList;}}/// <summary>/// Sets the current remote folder/// </summary>/// <param name="folder">The folder to be considered the current remote folder</param>/// <returns>Allways return True</returns>/// <remarks>if folder begins with '/' it starts on the root FTP folder, otherwise it is relative to current remote folder</remarks>publicboolChangeFolder(string folder){
_fileInfoListDirty =true;
folder = folder.Trim();if(folder ==null|| folder.Length ==0|| folder =="/"){
_workingFolder ="";returntrue;}if(folder.StartsWith("/")){//Sustitución completa de folder relativo
_workingFolder = folder.Substring(1);}else{//Append de folder relativo
_workingFolder +="/"+ folder;}if(_workingFolder.EndsWith("/")){
_workingFolder = _workingFolder.Substring(0, _workingFolder.Length -1);}if(_workingFolder.Length >0&&!_workingFolder.StartsWith("/")){
_workingFolder ="/"+ _workingFolder;}returntrue;}/// <summary>/// Gets the current remote folder/// </summary>/// <returns>The current remote folder name including the root folder</returns>publicstringGetCurrentFolder(){return RootFolder + _workingFolder;}/// <summary>/// 下载传ftp服务器/// Download an FTP file and saves it on a local file/// </summary>/// <param name="remoteFile">The name of the remote file to be downloaded</param>/// <param name="localFile">The name of the local file to where the remote file will be saved</param>/// <returns>True if successful, False if error</returns>publicboolGetFile(string remoteFile,string localFile){//antes lo leiamos en texto//string contenido = GetFileString(remoteFile, binaryMode);//if (contenido != null) {// File.WriteAllText(localFile, contenido);// return true;//}byte[] contenido =GetFileBinary(remoteFile);if(contenido !=null){
File.WriteAllBytes(localFile, contenido);returntrue;}returnfalse;}/// <summary>/// Gets the text contents of an FTP file/// </summary>/// <param name="remoteFile">The name of the remote file to be read</param>/// <returns>The contents of the file or Nothing if there was an error</returns>publicstringGetFileString(string remoteFile,bool binaryMode){var req =(FtpWebRequest)WebRequest.Create("ftp://"+ Server + RootFolder + _workingFolder +"/"+ remoteFile);
req.Proxy =null;
req.Credentials =newNetworkCredential(User, Password);
req.Method = WebRequestMethods.Ftp.DownloadFile;
req.UseBinary = binaryMode;using(FtpWebResponse resp =(FtpWebResponse)req.GetResponse()){RecordResponseStatus(resp);using(StreamReader reader =newStreamReader(resp.GetResponseStream())){return reader.ReadToEnd();}}}/// <summary>/// Gets the binary contents of an FTP file/// </summary>/// <param name="remoteFile">The name of the remote file to be read</param>/// <returns>The contents of the file or Nothing if there was an error</returns>publicbyte[]GetFileBinary(string remoteFile){var req =(FtpWebRequest)WebRequest.Create("ftp://"+ Server + RootFolder + _workingFolder +"/"+ remoteFile);
req.Proxy =null;
req.Credentials =newNetworkCredential(User, Password);
req.Method = WebRequestMethods.Ftp.DownloadFile;
req.UseBinary =true;using(FtpWebResponse resp =(FtpWebResponse)req.GetResponse()){RecordResponseStatus(resp);byte[] buffer =newbyte[32768];using(MemoryStream ms =newMemoryStream()){while(true){int read = resp.GetResponseStream().Read(buffer,0, buffer.Length);if(read <=0){return ms.ToArray();}
ms.Write(buffer,0, read);};};}}/// <summary>/// 计算本地系统和FTP服务器之间的时间差异/// Calculate the time diff between local system and the FTP server/// </summary>/// <returns></returns>publicSystem.TimeSpanGetTimeDiff(){string fileName ="integraasync.txt";DateTime current = DateTime.Now;DateTime fileDateTime =GetFileDateTime(fileName);//TimeSpan ret=TimeSpan.Zero;if(fileDateTime > DateTime.MinValue){DeleteFile(fileName);}if(UploadFileString(fileName,"integraasync")){
fileDateTime =GetFileDateTime(fileName);}else{thrownewApplicationException("Problemas al subir el archivo para calculo de diferencia de tiempo con servidor FTP");}return current - fileDateTime;}/// <summary>/// 返回服务器文件大小/// Gets the size of a file on the FTP Server (this method does not use the filelist cache)/// </summary>/// <param name="filename">file name</param>/// <returns>The file size</returns>publiclongGetFileSize(string filename){var req =(FtpWebRequest)WebRequest.Create("ftp://"+ Server + RootFolder + _workingFolder +"/"+ filename);
req.Proxy =null;
req.Credentials =newNetworkCredential(User, Password);
req.Method = WebRequestMethods.Ftp.GetFileSize;//TODO: get the resulting error code to report success or failureusing(FtpWebResponse resp =(FtpWebResponse)req.GetResponse()){RecordResponseStatus(resp);return resp.ContentLength;}}/// <summary>/// 删除服务器文件/// Deletes a file on the FTP Server/// </summary>/// <param name="filename">File name</param>/// <returns>Allways returns True</returns>publicboolDeleteFile(string filename){bool result =false;
_fileInfoListDirty =true;var req =(FtpWebRequest)WebRequest.Create("ftp://"+ Server + RootFolder + _workingFolder +"/"+ filename);
req.Proxy =null;
req.Credentials =newNetworkCredential(User, Password);
req.Method = WebRequestMethods.Ftp.DeleteFile;//TODO: get the resulting error code to report success or failuretry{using(WebResponse resp = req.GetResponse()){RecordResponseStatus((FtpWebResponse)resp);
result =(((FtpWebResponse)resp).StatusCode == FtpStatusCode.FileActionOK);}}catch(System.Net.WebException ex){if(ex.Responseis FtpWebResponse){RecordResponseStatus((FtpWebResponse)ex.Response);
result =(((FtpWebResponse)ex.Response).StatusCode == FtpStatusCode.FileActionOK);}else{throw ex;}};return result;}/// <summary>/// 重命名服务器文件/// </summary>/// <param name="filename"></param>/// <param name="newFilename"></param>/// <returns></returns>publicboolRenameFile(string filename,string newFilename){bool result =false;
_fileInfoListDirty =true;var req =(FtpWebRequest)WebRequest.Create("ftp://"+ Server + RootFolder + _workingFolder +"/"+ filename);
req.Proxy =null;
req.Credentials =newNetworkCredential(User, Password);
req.Method = WebRequestMethods.Ftp.Rename;
req.RenameTo = newFilename;using(FtpWebResponse resp =(FtpWebResponse)req.GetResponse()){RecordResponseStatus(resp);
result =(resp.StatusCode == FtpStatusCode.FileActionOK);}return result;}/// <summary>/// 获取文件创建时间/// </summary>/// <param name="filename"></param>/// <returns></returns>publicDateTimeGetFileDateTime(string filename){DateTime ret = DateTime.MinValue;if(getFileTimeStampNotSupported){return(GetFileDateTimeByListingFiles(filename));}var req =(FtpWebRequest)WebRequest.Create("ftp://"+ Server + RootFolder + _workingFolder +"/"+ filename);
req.Proxy =null;
req.Credentials =newNetworkCredential(User, Password);
req.Method = WebRequestMethods.Ftp.GetDateTimestamp;try{using(FtpWebResponse resp =(FtpWebResponse)req.GetResponse()){using(StreamReader reader =newStreamReader(resp.GetResponseStream())){RecordResponseStatus(resp);try{
Console.WriteLine(resp.ContentType.ToString());}catch(System.NotImplementedException){//Al parecer el servidor no soporta el metodo para obtener la fecha de un archivo// asi que usamos otro metodo
getFileTimeStampNotSupported =true;return(GetFileDateTimeByListingFiles(filename));};}}}catch(System.Net.WebException ex){FtpWebResponse ftpResponse =(FtpWebResponse)ex.Response;if(ftpResponse.StatusCode != FtpStatusCode.ActionNotTakenFileUnavailable){throw ex;}}return ret;}publicboolUploadFileString(string remoteFilename,string contents){byte[] fileContents = Encoding.UTF8.GetBytes(contents);returnUploadFileBytes(remoteFilename, fileContents);}/// <summary>/// 上传ftp服务器/// </summary>/// <param name="localFilename"></param>/// <param name="remoteFilename"></param>/// <returns></returns>publicboolUploadFile(string localFilename,string remoteFilename){//Lee el contenido del archivotry{/*StreamReader sourceStream =newStreamReader(localFilename);byte[] fileContents = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());
sourceStream.Close();*/FileStream fs =newFileStream(localFilename, FileMode.Open, FileAccess.Read);byte[] buffur =newbyte[fs.Length];
fs.Read(buffur,0,(int)fs.Length);returnUploadFileBytes(remoteFilename, buffur);}catch(Exception ex){
LastErrorMessage ="Error en UploadFile:"+GetExceptionMessage(ex);returnfalse;}}/// <summary>/// 把字节流写入ftp服务器/// </summary>/// <param name="remoteFilename"></param>/// <param name="fileContents"></param>/// <returns></returns>publicboolUploadFileBytes(string remoteFilename,byte[] fileContents){try{bool result =false;
_fileInfoListDirty =true;var req =(FtpWebRequest)WebRequest.Create("ftp://"+ Server + RootFolder + _workingFolder +"/"+ remoteFilename);
req.Proxy =null;
req.Credentials =newNetworkCredential(User, Password);
req.Method = WebRequestMethods.Ftp.UploadFile;//Lee el contenido del archivo
req.ContentLength = fileContents.Length;Stream requestStream = req.GetRequestStream();
requestStream.Write(fileContents,0, fileContents.Length);
requestStream.Close();FtpWebResponse response =(FtpWebResponse)req.GetResponse();RecordResponseStatus(response);//string responseStatus = response.StatusDescription;
result =(response.StatusCode == FtpStatusCode.ClosingData);
response.Close();return result;}catch(Exception ex){
LastErrorMessage ="Error en UploadFileBytes:"+GetExceptionMessage(ex);returnfalse;}}publicboolCreateFolder(string newFolderName){try{bool result =false;
_fileInfoListDirty =true;var req =(FtpWebRequest)WebRequest.Create("ftp://"+ Server + RootFolder + _workingFolder +"/"+ newFolderName);
req.Proxy =null;
req.Credentials =newNetworkCredential(User, Password);
req.Method = WebRequestMethods.Ftp.MakeDirectory;FtpWebResponse response =(FtpWebResponse)req.GetResponse();RecordResponseStatus(response);
result = response.StatusCode == FtpStatusCode.PathnameCreated;
response.Close();return result;}catch(Exception ex){
LastErrorMessage ="Error en CreateFolder \r\n"+GetExceptionMessage(ex);returnfalse;}}privateDateTimeGetFileDateTimeByListingFiles(string filename){DateTime ret = DateTime.MinValue;//Si es necesario actualiza la lista de archivos de la carpeta actualif(_workingFolder != _lastWorkingFolderListed || _fileInfoListDirty){GetFileListDetailed(null);}foreach(myFTPFileInfo fileInfo in _fileInfoList){if(fileInfo.Nombre.ToLower()== filename.ToLower()){return fileInfo.Fecha;}}return ret;}private myFTPFileInfo GetFileInfo(string filename){
myFTPFileInfo ret =null;//Si es necesario actualiza la lista de archivos de la carpeta actualif(_workingFolder != _lastWorkingFolderListed || _fileInfoListDirty){GetFileListDetailed(null);}foreach(myFTPFileInfo fileInfo in _fileInfoList){if(fileInfo.Nombre.ToLower()== filename.ToLower()){return fileInfo;}}return ret;}privatestringGetExceptionMessage(Exception ex){string ret ="";while(ex !=null){
ret +="==>"+ ex.Message +"\r\n";
ex = ex.InnerException;}return ret;}privatevoidRecordResponseStatus(FtpWebResponse response){
LastStatusCode = response.StatusCode;
LastStatusDescription = response.StatusDescription;}}publicinterfaceIDateTimeProvider{DateTimeGetCurrentDateTime();}classDefaultDateTimeProvider:IDateTimeProvider{DateTime IDateTimeProvider.GetCurrentDateTime(){return DateTime.Now;}}publicclass myFTPFileInfo
{publicbool IsFolder {get;set;}publicstring Nombre {get;set;}publiclong Tamaño {get;set;}publicDateTime Fecha {get;set;}publicstring Permisos {get;set;}publicstring Usuario {get;set;}publicstring Grupo {get;set;}privateIDateTimeProvider _dateTimeProvider;publicmyFTPFileInfo(string ftpFileInfo){
_dateTimeProvider =newDefaultDateTimeProvider();Parse(ftpFileInfo);}publicmyFTPFileInfo(string ftpFileInfo,IDateTimeProvider dateTimeProvider){if(dateTimeProvider !=null){
_dateTimeProvider = dateTimeProvider;}else{
_dateTimeProvider =newDefaultDateTimeProvider();}Parse(ftpFileInfo);}publicboolParse(string ftpFileInfo){Eliminamos los caracteres de espacio repetitivos//while (ftpFileInfo.Contains(" ")) {// ftpFileInfo=ftpFileInfo.replace(" "," ")//}var fileInfoData = ftpFileInfo.Split(newchar[]{' '},9, StringSplitOptions.RemoveEmptyEntries);if(fileInfoData.Length ==9){long tamañoArchivo;
IsFolder = fileInfoData[0].StartsWith("d");
Permisos = fileInfoData[0].Substring(1);
Usuario = fileInfoData[2];
Grupo = fileInfoData[3];long.TryParse(fileInfoData[4],out tamañoArchivo);
Tamaño = tamañoArchivo;
Fecha =ParseFTPDate(fileInfoData[5], fileInfoData[6], fileInfoData[7]);
Nombre = fileInfoData[8];returntrue;}else{
Permisos ="";
Usuario ="";
Grupo ="";
Tamaño =0;
Fecha = DateTime.MinValue;
Nombre ="";returnfalse;}}publicDateTimeParseFTPDate(string ftpMes,string ftpDia,string ftpAñoHora){DateTime ret;int dia =0, mes =0, año = _dateTimeProvider.GetCurrentDateTime().Year;string hora ="00:00";switch(ftpMes.Trim().ToLower()){case"jan":case"ene":
mes =1;break;case"feb":
mes =2;break;case"mar":
mes =3;break;case"apr":case"abr":
mes =4;break;case"may":
mes =5;break;case"jun":
mes =6;break;case"jul":
mes =7;break;case"aug":case"ago":
mes =8;break;case"sep":
mes =9;break;case"oct":
mes =10;break;case"nov":
mes =11;break;case"dec":case"dic":
mes =12;break;}int.TryParse(ftpDia,out dia);if(ftpAñoHora.Contains(":")){DateTime fechaCalculada = DateTime.MinValue;
hora = ftpAñoHora;//En el listado FTP aparecen sin año las fechas de los ultimos 365 dias.// Asi que la forma mas sencilla de lidiar con eso es que si la fecha calculada es mayor que la// fecha de hoy (considerando por default que al no especificar año se pone el año curso) entonces// significa que es fecha del año pasado
DateTime.TryParse(string.Format("{0:0000}/{1:00}/{2:00} 00:00:00.000", año, mes, dia),out fechaCalculada);if(fechaCalculada > _dateTimeProvider.GetCurrentDateTime()){
año -=1;}}else{int.TryParse(ftpAñoHora,out año);}
DateTime.TryParse(string.Format("{0:0000}/{1:00}/{2:00} {3}", año, mes, dia, hora),out ret);return ret;}}}
staticvoidMain(string[] args){//new Program().Test_Encrypt();FTPHelper m =newFTPHelper("localhost","root","1234","/");//List<string> list = m.GetFileList("/");//List<myFTPFileInfo> myFTPFiles = m.GetFileListDetailed();//List<myFTPFileInfo> info = m.GetFileListDetailed("");//bool changeFolder = m.ChangeFolder("dhaj");//m.GetFile("新建 Microsoft Access Database.accdb", @"C:\Users\root\Desktop\新建 Microsoft Access Database.accdb");//string str = m.GetFileString("新建 Microsoft Access Database.accdb", true);//long i = m.GetFileSize("新建 Microsoft Access Database.accdb");//bool deleteFile = m.DeleteFile("新建文件夹 - 副本 - 副本");//bool renameFile = m.RenameFile("新建 Microsoft Access Database.accdb", "a.accdb");//string date = m.GetFileDateTime("a.accdb").ToString("yyyy-MM-dd HH:mm:ss");bool uploadFile = m.UploadFile(@"C:\Users\root\Desktop\激活码、破解补丁.zip","a.zip");}