FtpWebRequest FTP异步下载、异步上传文件
异步下载:
public interface IPrimaryKey<T> { T GetKey(); } public class DownloadInfo : IPrimaryKey<string> { public string FtpResourceFilePath { get; set; } public string FileSaveLocalPath { get; set; } public bool IsDir { get; set; } public DateTime StartTime { get; set; } public int ProgressPercentage { get; set; } public string Speed { get; set; } public string GetKey() { return this.FtpResourceFilePath; } public List<DownloadInfo> SubFiles { get; set; } }
class Program { static readonly string FTP_USERNAME = string.Empty; static readonly string FTP_PASSWORD = string.Empty; static readonly string FTP_DOMAIN = string.Empty; // default 1 seconds. static readonly int FTP_REQUEST_TIMEOUT = 1; // default 1 seconds. static readonly int FTP_REQUEST_READWRITERTIMEOUT = 1; static Program() { FTP_REQUEST_TIMEOUT = Convert.ToInt32(ConfigurationManager.AppSettings.Get("FTP.Request.Timeout")); FTP_REQUEST_READWRITERTIMEOUT = Convert.ToInt32(ConfigurationManager.AppSettings.Get("FTP.Request.ReadWriteTimeout")); FTP_USERNAME = ConfigurationManager.AppSettings.Get("FTP.UserName"); FTP_PASSWORD = ConfigurationManager.AppSettings.Get("FTP.Password"); FTP_DOMAIN = ConfigurationManager.AppSettings.Get("FTP.Domain"); } static int DownloadCount = 0; static int CompleteCount = 0; static void Main(string[] args) { // default max parallel connection count is two in the .net framework. // sugesstion no over 1024. // and you also can add config node in app.config /* <configuration> * <system.net> * <connectionManagement> * <add address="*" maxconnection="512"/> * </connectionManagement> * </system> * </configuration> */ //System.Net.ServicePointManager.DefaultConnectionLimit = 512; string localRootPath = ConfigurationManager.AppSettings.Get("SaveRootPath"); List<DownloadInfo> rootFiles = GetSubFilesList(new DownloadInfo() { FtpResourceFilePath = "ftp://172.21.3.17//dd/MR", FileSaveLocalPath = string.Concat(localRootPath, "~TEMP\\Test1") }); DownloadFilesAsync(rootFiles); Console.ReadKey(); } private static void DownloadFilesAsync(List<DownloadInfo> items) { foreach (DownloadInfo task in items) { task.StartTime = DateTime.Now; if (task.IsDir) { task.SubFiles = GetSubFilesList(task); DownloadFilesAsync(task.SubFiles); } else { // try create the directory before donwload. TryCreateDirectory(task.FileSaveLocalPath); // Uri :the resource paht which will be download. // fileName :the dowload file save path; CreateWebClient().DownloadFileAsync(new Uri(task.FtpResourceFilePath), task.FileSaveLocalPath, task); } } } static WebClient CreateWebClient() { // 限制最多同时现在的线程数 LimitThreadAgain: if (DownloadCount - CompleteCount > 300) { Thread.Sleep(5000); goto LimitThreadAgain; } DownloadCount++; WebClient client = new WebClient(); client.Credentials = new NetworkCredential(FTP_USERNAME, FTP_PASSWORD, FTP_DOMAIN); client.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(client_DownloadFileCompleted); client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged); return client; } private static List<DownloadInfo> GetSubFilesList(DownloadInfo task) { List<DownloadInfo> subFiles = new List<DownloadInfo>(); FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri(task.FtpResourceFilePath)); request.Method = WebRequestMethods.Ftp.ListDirectoryDetails; request.Credentials = new NetworkCredential(FTP_USERNAME, FTP_PASSWORD, FTP_DOMAIN); request.UseBinary = true; request.Timeout = FTP_REQUEST_TIMEOUT; request.ReadWriteTimeout = FTP_REQUEST_READWRITERTIMEOUT; using (WebResponse response = request.GetResponse()) { using (StreamReader responseStream = new StreamReader(response.GetResponseStream(), System.Text.Encoding.Default)) { string line = responseStream.ReadLine(); while (line != null) { Console.WriteLine(line); string[] lineParitialArray = line.Split(new char[] { ' ' }); string theName = lineParitialArray[lineParitialArray.Length - 1]; if (line.IndexOf("<DIR>") != -1) { subFiles.Add(new DownloadInfo() { FtpResourceFilePath = string.Concat(task.FtpResourceFilePath, "/", theName), FileSaveLocalPath = string.Concat(task.FileSaveLocalPath, "\\", theName), IsDir = true }); } else { subFiles.Add(new DownloadInfo() { FtpResourceFilePath = string.Concat(task.FtpResourceFilePath, "/", theName), FileSaveLocalPath = string.Concat(task.FileSaveLocalPath, "\\", theName), IsDir = false }); } line = responseStream.ReadLine(); } } } return subFiles; } static void TryCreateDirectory(string filePath) { FileInfo fileInfo = new FileInfo(filePath); if (!fileInfo.Directory.Exists) { try { fileInfo.Directory.Create(); } catch (Exception ex) { Logger.Current.Error("an error thrown while create directory:\r\n{0}\r\n{1}", ex.Message, ex.StackTrace); } } } static void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) { DownloadInfo downloadInfo = e.UserState as DownloadInfo; downloadInfo.ProgressPercentage = e.ProgressPercentage; double downloadTime = (DateTime.Now - downloadInfo.StartTime).TotalSeconds; downloadInfo.Speed = GetFriendlyFileSize(e.BytesReceived / downloadTime, 2); Console.WriteLine("download precentage:{0}-{1}-{2}", downloadInfo.ProgressPercentage, downloadInfo.Speed, downloadInfo.FtpResourceFilePath); Logger.Current.Debug(string.Format("download precentage:{0}-{1}-{2}", downloadInfo.ProgressPercentage, downloadInfo.Speed, downloadInfo.FtpResourceFilePath)); } static void client_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) { if (e.Error != null) { if (e.Error.InnerException != null) Logger.Current.Error(string.Format("download error:{0}\r\n{1}", e.Error.InnerException.Message, e.Error.InnerException.StackTrace)); else Logger.Current.Error(string.Format("download error:{0}\r\n{1}", e.Error.Message, e.Error.StackTrace)); } DownloadInfo downloadInfo = e.UserState as DownloadInfo; Console.WriteLine("download complete:{0}", downloadInfo.FtpResourceFilePath); Logger.Current.Debug(string.Format("download complete:{0}", downloadInfo.FtpResourceFilePath)); CompleteCount++; } const double KB = 1024; const double MR = KB * 1024; const double GB = MR * 1024; const double TB = MR * 1024; const double PB = TB * 1024; static string GetFriendlyFileSize(double size, int decimals) { if (KB > size) return string.Format("{0}B", Math.Round(size, decimals)); else if (MR > size) return string.Format("{0}KB", Math.Round(size / KB, decimals)); else if (GB > size) return string.Format("{0}MR", Math.Round(size / MR, decimals)); else if (TB > size) return string.Format("{0}GB", Math.Round(size / GB, decimals)); else if (PB > size) return string.Format("{0}TB", Math.Round(size / TB, decimals)); else return string.Format("{0}PB", Math.Round(size / PB, decimals)); } }
异步上传:
// uploading #region uploading public class Program { public static void Main(string[] args) { FtpState state = new FtpState(); // the ftp url scheme like: ftp:// FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri("ftp://172.21.*.1*//dd/SHFBGuidedInstaller_2014.5.31.0.zip")); request.Method = WebRequestMethods.Ftp.UploadFile; //request.Method = WebRequestMethods.Ftp.DownloadFile; request.Credentials = new NetworkCredential("dn", "new.1234", "domain"); state.Request = request; state.FileName = @"C:\Users\dn\Desktop\SHFBGuidedInstaller_2014.5.31.0.zip"; //state.FileName = @"C:\Users\dn\Desktop\MR\SHFBGuidedInstaller_2014.5.31.0.zip"; // 获得WaitOne()对象 ManualResetEvent waitOjbect = state.OperationComplete; // 开始异步获取数据流 request.BeginGetRequestStream( new AsyncCallback(EndGetStreamCallback), state ); // 线程等待 waitOjbect.WaitOne(); if (state.OperationException != null) { throw state.OperationException; } else { Console.WriteLine("操作已经完成!"); } } public class FtpState { private ManualResetEvent wait; private FtpWebRequest request; private string fileName; private Exception opreationException = null; private string statusDescription; public FtpState() { wait = new ManualResetEvent(false); } public ManualResetEvent OperationComplete { get { return wait; } } public FtpWebRequest Request { get { return request; } set { request = value; } } public string FileName { get { return fileName; } set { fileName = value; } } public Exception OperationException { get { return opreationException; } set { opreationException = value; } } public string StatusDescription { get { return statusDescription; } set { statusDescription = value; } } } private static void EndGetStreamCallback(IAsyncResult result) { FtpState state = (FtpState)result.AsyncState; try { using (Stream requestStream = state.Request.EndGetRequestStream(result)) { const int bufferLength = 2048; byte[] buffer = new byte[bufferLength]; int count = 0; int readBytes = 0; using (FileStream stream = File.OpenRead(state.FileName)) { do { readBytes = stream.Read(buffer, 0, bufferLength); requestStream.Write(buffer, 0, readBytes); count += readBytes; } while (readBytes != 0); } Console.WriteLine("写入{0}字节到数据流中", count); state.Request.BeginGetResponse(new AsyncCallback(EndGetResponseCallback), state); } } catch (Exception ex) { Console.WriteLine("请求数据流失败!"); state.OperationException = ex; state.OperationComplete.Set(); } } private static void EndGetResponseCallback(IAsyncResult result) { FtpState state = (FtpState)result.AsyncState; try { FtpWebResponse response = (FtpWebResponse)state.Request.EndGetResponse(result); response.Close(); state.StatusDescription = response.StatusDescription; // 标记主线程结束 state.OperationComplete.Set(); } catch (Exception ex) { Console.WriteLine("获取请求回应失败!"); state.OperationException = ex; state.OperationComplete.Set(); } } #endregion }
基础才是编程人员应该深入研究的问题,比如:
1)List/Set/Map内部组成原理|区别
2)mysql索引存储结构&如何调优/b-tree特点、计算复杂度及影响复杂度的因素。。。
3)JVM运行组成与原理及调优
4)Java类加载器运行原理
5)Java中GC过程原理|使用的回收算法原理
6)Redis中hash一致性实现及与hash其他区别
7)Java多线程、线程池开发、管理Lock与Synchroined区别
8)Spring IOC/AOP 原理;加载过程的。。。
【+加关注】。