/// <summary> /// Download a single file directly. /// </summary> private async void DownloadFTPFileAsync( BackgroundDownloader downloader, NetworkCredential credential, FTPFileSystem item, StorageFile targetFile) { if (item.Size > 1048576) // 1M Byte { Progress<DownloadOperation> progressCallback = new Progress<DownloadOperation>(DownloadProgress); Uri urlWithCredential = item.Url; if (credential != null) { urlWithCredential = new Uri(item.Url.ToString().ToLower().Replace(@"ftp://", string.Format(@"ftp://{0}:{1}@", FTPFileSystem.EncodeUrl(credential.UserName), FTPFileSystem.EncodeUrl(credential.Password)))); } DownloadOperation download = downloader.CreateDownload( urlWithCredential, targetFile); ActiveBackgroundDownloaders.Add(download); await download.StartAsync().AsTask(progressCallback); } else { await FTPClient.DownloadFTPFileAsync(item, targetFile, credential) .ContinueWith(new Action<Task<DownloadCompletedEventArgs>>(DownloadProgress)); } }
/// <summary> /// Download a whole directory. /// </summary> private async void DownloadFTPDirectoryAsync( BackgroundDownloader downloader, NetworkCredential credential, FTPFileSystem item, StorageFolder targetFolder) { // List the sub folders and files. var subItems = await this.ListFtpContentAsync(item.Url, credential); // Download the sub folders and files. foreach (var subitem in subItems) { if (subitem.IsDirectory) { // Create a local folder. var subFolder = await targetFolder.CreateFolderAsync(subitem.Name, CreationCollisionOption.ReplaceExisting); // Download the whole folder. DownloadFTPDirectoryAsync(downloader, credential, subitem, subFolder); } else { // Create a local file. var file = await targetFolder.CreateFileAsync(subitem.Name, CreationCollisionOption.GenerateUniqueName); // Download the file. DownloadFTPFileAsync(downloader, credential, subitem, file); } } }
/// <summary> /// Get an FTPFileSystem from the recordString. /// </summary> public static FTPFileSystem ParseRecordString(Uri baseUrl, string recordString, FTPDirectoryListingStyle type) { FTPFileSystem fileSystem = null; if (type == FTPDirectoryListingStyle.UNIX) { fileSystem = ParseUNIXRecordString(recordString); } else { fileSystem = ParseMSDOSRecordString(recordString); } string encodedName = EncodeUrl(fileSystem.Name); // Add "/" to the url if it is a directory fileSystem.Url = new Uri(baseUrl, encodedName + (fileSystem.IsDirectory ? "/" : string.Empty)); return(fileSystem); }
/// <summary> /// 12-13-10 12:41PM <DIR> Folder A /// </summary> /// <param name="recordString"></param> /// <returns></returns> static FTPFileSystem ParseMSDOSRecordString(string recordString) { FTPFileSystem fileSystem = new FTPFileSystem(); fileSystem.OriginalRecordString = recordString.Trim(); fileSystem.DirectoryListingStyle = FTPDirectoryListingStyle.MSDOS; // The segments is like "12-13-10", "", "12:41PM", "", "","", "", // "", "", "<DIR>", "", "", "", "", "", "", "", "", "", "Folder", "A". string[] segments = fileSystem.OriginalRecordString.Split(' '); int index = 0; // The date segment is like "12-13-10" instead of "12-13-2010" if Four-digit years // is not checked in IIS. string dateSegment = segments[index]; string[] dateSegments = dateSegment.Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries); int month = int.Parse(dateSegments[0]); int day = int.Parse(dateSegments[1]); int year = int.Parse(dateSegments[2]); // If year >=50 and year <100, then it means the year 19** if (year >= 50 && year < 100) { year += 1900; } // If year <50, then it means the year 20** else if (year < 50) { year += 2000; } // Skip the empty segments. while (segments[++index] == string.Empty) { } // The time segment. string timesegment = segments[index]; fileSystem.ModifiedTime = DateTime.Parse(string.Format("{0}-{1}-{2} {3}", year, month, day, timesegment)); // Skip the empty segments. while (segments[++index] == string.Empty) { } // The size or directory segment. // If this segment is "<DIR>", then it means a directory, else it means the // file size. string sizeOrDirSegment = segments[index]; fileSystem.IsDirectory = sizeOrDirSegment.Equals("<DIR>", StringComparison.OrdinalIgnoreCase); // If this fileSystem is a file, then the size is larger than 0. if (!fileSystem.IsDirectory) { fileSystem.Size = long.Parse(sizeOrDirSegment); } // Skip the empty segments. while (segments[++index] == string.Empty) { } // Calculate the index of the file name part in the original string. int filenameIndex = 0; for (int i = 0; i < index; i++) { // "" represents ' ' in the original string. if (segments[i] == string.Empty) { filenameIndex += 1; } else { filenameIndex += segments[i].Length + 1; } } // The file name may include many segments because the name can contain ' '. fileSystem.Name = fileSystem.OriginalRecordString.Substring(filenameIndex).Trim(); return(fileSystem); }
/// <summary> /// The recordString is like /// Directory: drwxrwxrwx 1 owner group 0 Dec 13 11:25 Folder A /// File: -rwxrwxrwx 1 owner group 1024 Dec 13 11:25 File B /// NOTE: The date segment does not contains year. /// </summary> static FTPFileSystem ParseUNIXRecordString(string recordString) { FTPFileSystem fileSystem = new FTPFileSystem(); fileSystem.OriginalRecordString = recordString.Trim(); fileSystem.DirectoryListingStyle = FTPDirectoryListingStyle.UNIX; // The segments is like "drwxrwxrwx", "", "", "1", "owner", "", "", "", // "group", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", // "0", "Dec", "13", "11:25", "Folder", "A". string[] segments = fileSystem.OriginalRecordString.Split(' '); int index = 0; // The permission segment is like "drwxrwxrwx". string permissionsegment = segments[index]; // If the property start with 'd', then it means a directory. fileSystem.IsDirectory = permissionsegment[0] == 'd'; // Skip the empty segments. while (segments[++index] == string.Empty) { } // Skip the directories segment. // Skip the empty segments. while (segments[++index] == string.Empty) { } // Skip the owner segment. // Skip the empty segments. while (segments[++index] == string.Empty) { } // Skip the group segment. // Skip the empty segments. while (segments[++index] == string.Empty) { } // If this fileSystem is a file, then the size is larger than 0. fileSystem.Size = long.Parse(segments[index]); // Skip the empty segments. while (segments[++index] == string.Empty) { } // The month segment. string monthsegment = segments[index]; // Skip the empty segments. while (segments[++index] == string.Empty) { } // The day segment. string daysegment = segments[index]; // Skip the empty segments. while (segments[++index] == string.Empty) { } // The time segment. string timesegment = segments[index]; fileSystem.ModifiedTime = DateTime.Parse(string.Format("{0} {1} {2} ", timesegment, monthsegment, daysegment)); // Skip the empty segments. while (segments[++index] == string.Empty) { } // Calculate the index of the file name part in the original string. int filenameIndex = 0; for (int i = 0; i < index; i++) { // "" represents ' ' in the original string. if (segments[i] == string.Empty) { filenameIndex += 1; } else { filenameIndex += segments[i].Length + 1; } } // The file name may include many segments because the name can contain ' '. fileSystem.Name = fileSystem.OriginalRecordString.Substring(filenameIndex).Trim(); return(fileSystem); }
/// <summary> /// Download a single file from FTP server using WebRequest. /// </summary> public static async Task <DownloadCompletedEventArgs> DownloadFTPFileAsync(FTPFileSystem item, StorageFile targetFile, ICredentials credential) { var result = new DownloadCompletedEventArgs { RequestFile = item.Url, LocalFile = targetFile, Error = null }; // This request is FtpWebRequest in fact. WebRequest request = WebRequest.Create(item.Url); if (credential != null) { request.Credentials = credential; } request.Proxy = WebRequest.DefaultWebProxy; // Set the method to Download File request.Method = "RETR"; try { // Open the file for write. using (IRandomAccessStream fileStream = await targetFile.OpenAsync(FileAccessMode.ReadWrite)) { // Get response. using (WebResponse response = await request.GetResponseAsync()) { // Get response stream. using (Stream responseStream = response.GetResponseStream()) { byte[] downloadBuffer = new byte[2048]; int bytesSize = 0; // Download the file until the download is completed. while (true) { // Read a buffer of data from the stream. bytesSize = responseStream.Read(downloadBuffer, 0, downloadBuffer.Length); if (bytesSize == 0) { break; } // Write buffer to the file. await fileStream.WriteAsync(downloadBuffer.AsBuffer()); } } } } } catch (Exception ex) { result.Error = ex; } return(result); }