PageRenderTime 44ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/Visual Studio 2008/CSFTPDownload/FTPDownloadClient.cs

#
C# | 294 lines | 195 code | 49 blank | 50 comment | 21 complexity | 7730f336f64fc394e00f46fc28044f52 MD5 | raw file
  1. /****************************** Module Header ******************************\
  2. * Module Name: FTPDownloadClient.cs
  3. * Project: CSFTPDownload
  4. * Copyright (c) Microsoft Corporation.
  5. *
  6. * This class is used to download files from a FTP server. When the download
  7. * starts, it will download the file in a background thread. The downloaded
  8. * data is stored in a MemoryStream first, and then written to local file.
  9. *
  10. *
  11. * This source is subject to the Microsoft Public License.
  12. * See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
  13. * All other rights reserved.
  14. *
  15. * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
  16. * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
  17. * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
  18. \***************************************************************************/
  19. using System;
  20. using System.Collections.Generic;
  21. using System.IO;
  22. using System.Net;
  23. using System.Threading;
  24. namespace CSFTPDownload
  25. {
  26. public partial class FTPClientManager
  27. {
  28. public class FTPDownloadClient
  29. {
  30. // 2M bytes.
  31. public const int MaxCacheSize = 2097152;
  32. // 2K bytes.
  33. public const int BufferSize = 2048;
  34. FTPClientManager manager;
  35. public event EventHandler<FileDownloadCompletedEventArgs>
  36. FileDownloadCompleted;
  37. public event EventHandler AllFilesDownloadCompleted;
  38. public FTPDownloadClient(FTPClientManager manager)
  39. {
  40. if (manager == null)
  41. {
  42. throw new ArgumentNullException("FTPClientManager cannot be null.");
  43. }
  44. this.manager = manager;
  45. }
  46. /// <summary>
  47. /// Download files, directories and their subdirectories.
  48. /// </summary>
  49. public void DownloadDirectoriesAndFiles(IEnumerable<FTPFileSystem> files,
  50. string localPath)
  51. {
  52. if (files == null)
  53. {
  54. throw new ArgumentNullException(
  55. "The files to download cannot be null.");
  56. }
  57. // Create a thread to download data.
  58. ParameterizedThreadStart threadStart =
  59. new ParameterizedThreadStart(StartDownloadDirectoriesAndFiles);
  60. Thread downloadThread = new Thread(threadStart);
  61. downloadThread.IsBackground = true;
  62. downloadThread.Start(new object[] { files, localPath });
  63. }
  64. /// <summary>
  65. /// Download files, directories and their subdirectories.
  66. /// </summary>
  67. void StartDownloadDirectoriesAndFiles(object state)
  68. {
  69. var paras = state as object[];
  70. IEnumerable<FTPFileSystem> files = paras[0] as IEnumerable<FTPFileSystem>;
  71. string localPath = paras[1] as string;
  72. foreach (var file in files)
  73. {
  74. DownloadDirectoryOrFile(file, localPath);
  75. }
  76. this.OnAllFilesDownloadCompleted(EventArgs.Empty);
  77. }
  78. /// <summary>
  79. /// Download a single file or directory.
  80. /// </summary>
  81. void DownloadDirectoryOrFile(FTPFileSystem fileSystem, string localPath)
  82. {
  83. // Download the file directly.
  84. if (!fileSystem.IsDirectory)
  85. {
  86. DownloadFile(fileSystem, localPath);
  87. }
  88. // Download a directory.
  89. else
  90. {
  91. // Construct the directory Path.
  92. string directoryPath = localPath + "\\" + fileSystem.Name;
  93. if (!Directory.Exists(directoryPath))
  94. {
  95. Directory.CreateDirectory(directoryPath);
  96. }
  97. // Get the sub directories and files.
  98. var subDirectoriesAndFiles =
  99. this.manager.GetSubDirectoriesAndFiles(fileSystem.Url);
  100. // Download the files in the folder and sub directories.
  101. foreach (var subFile in subDirectoriesAndFiles)
  102. {
  103. DownloadDirectoryOrFile(subFile, directoryPath);
  104. }
  105. }
  106. }
  107. /// <summary>
  108. /// Download a single file directly.
  109. /// </summary>
  110. void DownloadFile(FTPFileSystem file, string localPath)
  111. {
  112. if (file.IsDirectory)
  113. {
  114. throw new ArgumentException(
  115. "The FTPFileSystem to download is a directory in fact");
  116. }
  117. string destPath = localPath + "\\" + file.Name;
  118. // Create a request to the file to be downloaded.
  119. FtpWebRequest request = WebRequest.Create(file.Url) as FtpWebRequest;
  120. request.Credentials = this.manager.Credentials;
  121. // Download file.
  122. request.Method = WebRequestMethods.Ftp.DownloadFile;
  123. FtpWebResponse response = null;
  124. Stream responseStream = null;
  125. MemoryStream downloadCache = null;
  126. try
  127. {
  128. // Retrieve the response from the server and get the response stream.
  129. response = request.GetResponse() as FtpWebResponse;
  130. this.manager.OnNewMessageArrived(new NewMessageEventArg
  131. {
  132. NewMessage = response.StatusDescription
  133. });
  134. responseStream = response.GetResponseStream();
  135. // Cache data in memory.
  136. downloadCache = new MemoryStream(FTPDownloadClient.MaxCacheSize);
  137. byte[] downloadBuffer = new byte[FTPDownloadClient.BufferSize];
  138. int bytesSize = 0;
  139. int cachedSize = 0;
  140. // Download the file until the download is completed.
  141. while (true)
  142. {
  143. // Read a buffer of data from the stream.
  144. bytesSize = responseStream.Read(downloadBuffer, 0,
  145. downloadBuffer.Length);
  146. // If the cache is full, or the download is completed, write
  147. // the data in cache to local file.
  148. if (bytesSize == 0
  149. || MaxCacheSize < cachedSize + bytesSize)
  150. {
  151. try
  152. {
  153. // Write the data in cache to local file.
  154. WriteCacheToFile(downloadCache, destPath, cachedSize);
  155. // Stop downloading the file if the download is paused,
  156. // canceled or completed.
  157. if (bytesSize == 0)
  158. {
  159. break;
  160. }
  161. // Reset cache.
  162. downloadCache.Seek(0, SeekOrigin.Begin);
  163. cachedSize = 0;
  164. }
  165. catch (Exception ex)
  166. {
  167. string msg = string.Format(
  168. "There is an error while downloading {0}. "
  169. + " See InnerException for detailed error. ",
  170. file.Url);
  171. ApplicationException errorException
  172. = new ApplicationException(msg, ex);
  173. // Fire the DownloadCompleted event with the error.
  174. ErrorEventArgs e = new ErrorEventArgs
  175. {
  176. ErrorException = errorException
  177. };
  178. this.manager.OnErrorOccurred(e);
  179. return;
  180. }
  181. }
  182. // Write the data from the buffer to the cache in memory.
  183. downloadCache.Write(downloadBuffer, 0, bytesSize);
  184. cachedSize += bytesSize;
  185. }
  186. var fileDownloadCompletedEventArgs = new FileDownloadCompletedEventArgs
  187. {
  188. LocalFile = new FileInfo(destPath),
  189. ServerPath = file.Url
  190. };
  191. this.OnFileDownloadCompleted(fileDownloadCompletedEventArgs);
  192. }
  193. finally
  194. {
  195. if (response != null)
  196. {
  197. response.Close();
  198. }
  199. if (responseStream != null)
  200. {
  201. responseStream.Close();
  202. }
  203. if (downloadCache != null)
  204. {
  205. downloadCache.Close();
  206. }
  207. }
  208. }
  209. /// <summary>
  210. /// Write the data in cache to local file.
  211. /// </summary>
  212. void WriteCacheToFile(MemoryStream downloadCache, string downloadPath,
  213. int cachedSize)
  214. {
  215. using (FileStream fileStream = new FileStream(downloadPath,
  216. FileMode.Append))
  217. {
  218. byte[] cacheContent = new byte[cachedSize];
  219. downloadCache.Seek(0, SeekOrigin.Begin);
  220. downloadCache.Read(cacheContent, 0, cachedSize);
  221. fileStream.Write(cacheContent, 0, cachedSize);
  222. }
  223. }
  224. protected virtual void OnFileDownloadCompleted(FileDownloadCompletedEventArgs e)
  225. {
  226. if (FileDownloadCompleted != null)
  227. {
  228. FileDownloadCompleted(this, e);
  229. }
  230. }
  231. protected virtual void OnAllFilesDownloadCompleted(EventArgs e)
  232. {
  233. if (AllFilesDownloadCompleted != null)
  234. {
  235. AllFilesDownloadCompleted(this, e);
  236. }
  237. }
  238. }
  239. }
  240. }