/// <summary> /// Sets up the initial values of the downloader. /// </summary> /// <param name="savePath">The path to which to save the file. /// If <paramref name="useDefaultFileName"/> is <c>false</c>, this value should be a complete /// path, including filename. If <paramref name="useDefaultFileName"/> is <c>true</c>, /// this value should be the directory in which to save the file.</param> /// <param name="useDefaultFileName">Whether to use the file name suggested by the server.</param> private void Initialize(string savePath, bool useDefaultFileName) { _metadata = GetMetadata(URL); var strFilename = useDefaultFileName ? _metadata.SuggestedFileName : Path.GetFileName(savePath); strFilename = Uri.UnescapeDataString(strFilename); foreach (var chrInvalid in Path.GetInvalidFileNameChars()) { strFilename = strFilename.Replace(chrInvalid, '_'); } savePath = Path.Combine(savePath, strFilename); _savePath = savePath + ".partial"; _fileMetadataPath = savePath + ".parts"; var metaDataPathExists = File.Exists(_fileMetadataPath); if (!_metadata.SupportsResume) { if (metaDataPathExists) { File.Delete(_fileMetadataPath); } if (File.Exists(_savePath)) { File.Delete(_savePath); } } //get the list of ranges we have already downloaded var rgsRanges = new RangeSet(); if (metaDataPathExists) { var strRanges = File.ReadAllLines(_fileMetadataPath); foreach (var strRange in strRanges) { var strCleanRange = strRange.Trim().Trim('\0'); if (string.IsNullOrEmpty(strCleanRange)) { continue; } rgsRanges.AddRange(Range.Parse(strCleanRange)); } } _initialByteCount = rgsRanges.TotalSize; ResumedByteCount = rgsRanges.TotalSize / 1024; }
/// <summary> /// Sets up the initial values of the downloader. /// </summary> /// <param name="p_strSavePath">The path to which to save the file. /// If <paramref name="p_booUseDefaultFileName"/> is <c>false</c>, this value should be a complete /// path, including filename. If <paramref name="p_booUseDefaultFileName"/> is <c>true</c>, /// this value should be the directory in which to save the file.</param> /// <param name="p_booUseDefaultFileName">Whether to use the file name suggested by the server.</param> private void Initialize(string p_strSavePath, bool p_booUseDefaultFileName) { m_fmdInfo = GetMetadata(); string strFilename = p_booUseDefaultFileName ? m_fmdInfo.SuggestedFileName : Path.GetFileName(p_strSavePath); strFilename = Uri.UnescapeDataString(strFilename); foreach (char chrInvalid in Path.GetInvalidFileNameChars()) { strFilename = strFilename.Replace(chrInvalid, '_'); } p_strSavePath = Path.Combine(p_strSavePath, strFilename); m_strSavePath = p_strSavePath + ".partial"; m_strFileMetadataPath = p_strSavePath + ".parts"; if (!m_fmdInfo.SupportsResume) { File.Delete(m_strFileMetadataPath); File.Delete(m_strSavePath); } //get the list of ranges we have already downloaded RangeSet rgsRanges = new RangeSet(); if (File.Exists(m_strFileMetadataPath)) { string[] strRanges = File.ReadAllLines(m_strFileMetadataPath); foreach (string strRange in strRanges) { string strCleanRange = strRange.Trim().Trim('\0'); if (String.IsNullOrEmpty(strCleanRange)) { continue; } rgsRanges.AddRange(Range.Parse(strCleanRange)); } } m_intInitialByteCount = rgsRanges.TotalSize; m_intInitialDownloadedByteCount = rgsRanges.TotalSize / 1024; }
/// <summary> /// Starts the file download. /// </summary> public void StartDownload() { Trace.TraceInformation($"[{URL}] Downloading."); if (!FileExists) { throw new FileNotFoundException("The file to download does not exist.", URL.ToString()); } int intConnectionsToUse = _metadata.SupportsResume ? _maxConnections : 1; if (ServicePointManager.DefaultConnectionLimit < 1) { throw new Exception(string.Format("Only {0} connections can be created to the same file; {1} are wanted.", ServicePointManager.DefaultConnectionLimit, 1)); } if (ServicePointManager.DefaultConnectionLimit < intConnectionsToUse) { intConnectionsToUse = ServicePointManager.DefaultConnectionLimit; } //get the list of ranges we have not already downloaded RangeSet rgsMissingRanges = new RangeSet(); rgsMissingRanges.AddRange(new Range(0, _metadata.Length - 1)); if (File.Exists(_fileMetadataPath)) { string[] strRanges = File.ReadAllLines(_fileMetadataPath); foreach (string strRange in strRanges) { string strCleanRange = strRange.Trim().Trim('\0'); if (string.IsNullOrEmpty(strCleanRange)) { continue; } rgsMissingRanges.RemoveRange(Range.Parse(strCleanRange)); } } else if (File.Exists(_savePath)) { File.Delete(_savePath); } int intMinBlockSize = (int)Math.Min((ulong)_minBlockSize, rgsMissingRanges.TotalSize); int intBaseBlockSize = (int)Math.Max(rgsMissingRanges.TotalSize / (ulong)intConnectionsToUse, (ulong)intMinBlockSize); if (intConnectionsToUse > 1) { intBaseBlockSize = Math.Min(intBaseBlockSize, MaxBlockSize); } //break the ranges into blocks to be downloaded foreach (Range rngNeeded in rgsMissingRanges) { //find out how many blocks will fit into the range int intBlockCount = (int)(rngNeeded.Size / (ulong)intBaseBlockSize); if (intBlockCount == 0) { intBlockCount = 1; } //there is likely to be some remainder (there are likely a fractional number of blocks // in the range), so lets distrubute the remainder amongst all of the blocks // we do this by elarging our blocksize ulong intBlockSize = (ulong)Math.Ceiling(rngNeeded.Size / (double)intBlockCount); ulong intBlockStart = rngNeeded.StartByte; for (; intBlockStart + intBlockSize < rngNeeded.EndByte; intBlockStart += intBlockSize) { _requiredBlocks.Enqueue(new Range(intBlockStart, intBlockStart + intBlockSize - 1)); } _requiredBlocks.Enqueue(new Range(intBlockStart, rngNeeded.EndByte)); } _writer = new FileWriter(_savePath, _fileMetadataPath); _startTime = DateTime.Now; //spawn the downloading threads int intRequiredBlocks = _requiredBlocks.Count; lock (_downloaders) { for (int i = 0; i < (intRequiredBlocks < intConnectionsToUse ? intRequiredBlocks : intConnectionsToUse); i++) { BlockDownloader bdrDownloader = new BlockDownloader(this, _metadata, _writer, _writeBufferSize, _userAgent); bdrDownloader.FinishedDownloading += new EventHandler(Downloader_FinishedDownloading); bdrDownloader.Start(); _downloaders.Add(bdrDownloader); } } }