public class MultiDownload
{
#region 初始化参数
private int bufferSize = 512;//缓冲池大小
private int threadNum;//线程数
private string Url;//接受文件的URL
//private List<string> Urls;
private bool HasMerge;//文件合并标志
private string DestFileName;
private long receiveSize;//已经接收到的字节数
private long fileSizeAll;//文件字节数
private int RowIndex;//任务索引
private List<ThreadInfo> threadinfos;
private object lockPercent;//用于在加载下载进度是上锁
private object lockFile;
#endregion 初始化参数
/// <summary>
/// 下载进度
/// </summary>
/// <param name="rowIndex">任务索引</param>
/// <param name="percent">进度</param>
public delegate void DownloadingPercent(double percent);
public event DownloadingPercent OnDownloadingPercent;
/// <summary>
/// 源文件大小
/// </summary>
/// <param name="rowIndex"></param>
/// <param name="size"></param>
public delegate void UpdateSrcFileSize(int rowIndex, long size);
public event UpdateSrcFileSize OnUpdateSrcFileSize;
/// <summary>
/// 响应开始时间和结束时间的事件
/// </summary>
/// <param name="date"></param>
public delegate void GetRunTime(DateTime date);
public event GetRunTime OnGetStartTime;
public event GetRunTime OnGetFinalTime;
/// <summary>
/// 响应改变控件状态事件,变为可使用
/// </summary>
public delegate void SetControlStaus();
public event SetControlStaus OnSetControlStaus;
public MultiDownload()
{
threadinfos = new List<ThreadInfo>();
lockPercent = new object();
lockFile = new object();
}
/// <summary>
/// Http方式多线程下载一个文件
/// </summary>
/// <param name="srcFileUrl">文件地址</param>
/// <param name="destFileName">保存全名</param>
/// <param name="maxThreadNum">线程数</param>
/// <param name="rowIndex">任务索引</param>
public void DownloadFile(string srcFileUrl, string destFileName, int maxThreadNum = 5, int rowIndex = 0)
{
if (OnGetStartTime != null)
OnGetStartTime(DateTime.Now);
Url = srcFileUrl;
DestFileName = destFileName;
RowIndex = rowIndex;
threadNum = maxThreadNum;//多少个线程下载
receiveSize = 0;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.Url);
fileSizeAll = request.GetResponse().ContentLength;
request.Abort();
if (OnUpdateSrcFileSize != null)
OnUpdateSrcFileSize(0, fileSizeAll);
//初始化多线程
List<Task> taskList = new List<Task>();
//每个线程平均分配文件大小
long pieceSize = (long)fileSizeAll / threadNum + (long)fileSizeAll % threadNum;
for (int i = 0; i < threadNum; i++)
{
var resetEvent = new ManualResetEvent(false);
ThreadInfo currentThread = new ThreadInfo();
currentThread.ThreadId = i;
currentThread.ThreadStatus = false;
string filename = System.IO.Path.GetFileName(DestFileName);//带拓展名的文件名
string dir = System.IO.Path.GetDirectoryName(DestFileName); //返回文件所在目录
currentThread.TmpFileName = string.Format($"{dir}{i}_{filename}.tmp");
currentThread.Url = Url;
currentThread.FileName = DestFileName;
long startPosition = (i * pieceSize);
currentThread.StartPosition = startPosition == 0 ? 0 : startPosition + 1;
currentThread.FileSize = startPosition + pieceSize;
threadinfos.Add(currentThread);
taskList.Add(Task.Factory.StartNew(() =>
{
ReceiveHttp(currentThread);
}));
}
TaskFactory taskFactory = new TaskFactory();
taskList.Add(taskFactory.ContinueWhenAll(taskList.ToArray(), tArray =>
{
//启动合并线程
MergeFile();
threadinfos.Clear();
taskList.Clear();
}));
}
/// <summary>
/// Http方式接收一个区块
/// </summary>
private void ReceiveHttp(object thread)
{
FileStream fs = null;
Stream ns = null;
try
{
ThreadInfo currentThread = (ThreadInfo)thread;
byte[] buffer = new byte[bufferSize]; // 接收缓冲区
if (!File.Exists(currentThread.FileName))
{
fs = new FileStream(currentThread.TmpFileName, FileMode.Create);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(currentThread.Url);
request.Headers["Accept-Ranges"] = "bytes";
request.AddRange(currentThread.StartPosition, currentThread.FileSize);
ns = request.GetResponse().GetResponseStream();
int readSize = ns.Read(buffer, 0, bufferSize);
while (readSize > 0)
{
fs.Write(buffer, 0, readSize);
buffer = new byte[bufferSize];
readSize = ns.Read(buffer, 0, buffer.Length);
receiveSize += readSize;
double percent = (double)receiveSize / (double)fileSizeAll * 100;
//Debug.WriteLine($"下载进度:{percent}");
if (OnDownloadingPercent != null)
OnDownloadingPercent(percent);//触发下载进度事件
}
}
currentThread.ThreadStatus = true;
}
catch //这里不用处理异常,如果等待超时了,会自动继续等待到可以下载为止
{
//throw ex;
}
finally
{
fs?.Close();
ns?.Close();
}
}
/// <summary>
/// 合并文件
/// </summary>
private void MergeFile()
{
int readSize;
string downFileNamePath = DestFileName;
byte[] buffer = new byte[bufferSize];
int length = 0;
using (FileStream fs = new FileStream(downFileNamePath, FileMode.Create))
{
foreach (var item in threadinfos.OrderBy(o => o.ThreadId))
{
if (!File.Exists(item.TmpFileName)) continue;
var tempFile = item.TmpFileName;
Debug.WriteLine($"当前合并文件:{tempFile}");
using (FileStream tempStream = new FileStream(tempFile, FileMode.Open))
{
while ((length = tempStream.Read(buffer, 0, buffer.Length)) > 0)
{
fs.Write(buffer, 0, length);
}
tempStream.Flush();
}
try
{
File.Delete(item.TmpFileName);
}
catch
{
}
}
}
if (OnGetFinalTime != null)
OnGetFinalTime(DateTime.Now);
if (OnSetControlStaus != null)
OnSetControlStaus();
}
/// <summary>
/// 释放资源
/// </summary>
public void Dispose()
{
foreach (var item in threadinfos)
{
File.Delete(item.TmpFileName);
}
}
}
internal class ThreadInfo
{
public int ThreadId { get; set; }
public bool ThreadStatus { get; set; }
public long StartPosition { get; set; }
public long FileSize { get; set; }
public string Url { get; set; }
public string TmpFileName { get; set; }
public string FileName { get; set; }
public int Times { get; set; }
}
“相关推荐”对你有帮助么?
-
非常没帮助
-
没帮助
-
一般
-
有帮助
-
非常有帮助
提交