/// <summary> /// 下载到某个文件夹,仅提供 Windows 下使用,也仅在 Windows 下经过测试 /// </summary> /// <param name="url"></param> /// <param name="downloadFolder"></param> /// <param name="tempFolder">如不传,将使用 <paramref name="downloadFolder"/>作为下载存放的临时文件夹</param> /// <param name="logger">下载时的内部日志,默认将使用 Debug 输出</param> /// <param name="progress">下载进度</param> /// <param name="sharedArrayPool">共享缓存数组池,默认使用 ArrayPool 池</param> /// <param name="bufferLength">缓存的数组长度,默认是 65535 的长度</param> /// <param name="stepTimeOut">每一步 每一分段下载超时时间 默认 10 秒</param> /// <returns></returns> public static async Task <FileInfo> DownloadFileToFolderAsync(string url, DirectoryInfo downloadFolder, DirectoryInfo?tempFolder = null, ILogger <SegmentFileDownloader>?logger = null, IProgress <DownloadProgress>?progress = null, ISharedArrayPool?sharedArrayPool = null, int bufferLength = ushort.MaxValue, TimeSpan?stepTimeOut = null) { #if !NETFRAMEWORK // 也许会在非 Windows 下系统使用 if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { throw new PlatformNotSupportedException($"当前方法仅供 Windows 系统使用"); } #endif downloadFolder.Create(); tempFolder ??= downloadFolder; tempFolder.Create(); // 创建临时文件 var fileName = FileNameHelper.GuessFileNameFromUrl(url, fallbackName: Path.GetRandomFileName()); var downloadFile = new FileInfo(Path.Combine(tempFolder.FullName, fileName)); var segmentFileDownloader = new InnerSegmentFileDownloader(url, downloadFile, logger, progress, sharedArrayPool, bufferLength, stepTimeOut); await segmentFileDownloader.DownloadFileAsync(); // 下载完成了之后,尝试移动文件夹 // 优先使用服务器返回的文件名 var finallyFileName = segmentFileDownloader.ServerSuggestionFileName; if (string.IsNullOrEmpty(finallyFileName)) { finallyFileName = fileName; } var finallyFile = new FileInfo(Path.Combine(downloadFolder.FullName, finallyFileName)); if (finallyFile.FullName.Equals(downloadFile.FullName, StringComparison.OrdinalIgnoreCase)) { // 这里在 Windows 下可以忽略文件大小写等,但是在 Linux 下就不可以 // 好在此方法当前仅给 Windows 使用 return(finallyFile); } if (finallyFile.Exists) { // 重新加个名字,理论上这个名字不会重叠 finallyFile = new FileInfo(Path.Combine(finallyFile.Directory.FullName, Path.GetFileNameWithoutExtension(finallyFile.FullName) + Path.GetRandomFileName() + finallyFile.Extension)); } if (Path.GetPathRoot(finallyFile.FullName) == Path.GetPathRoot(downloadFile.FullName)) { // 相同的驱动器,移动就可以了 // 在非 Windows 下有驱动器么? downloadFile.MoveTo(finallyFile.FullName); } else { // 谁这么无聊,用的下载文件和最终文件还不相同 // 那就先复制一下再删除原来的文件 downloadFile.CopyTo(finallyFile.FullName); downloadFile.Delete(); } return(finallyFile); }