让下载类纯粹一些,在下载类的内部,不再保存为文件,如果要保存,那是用户自己的事情,提供了两种形式返回下载的内容:方法的返回值和事件参数。
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Threading;
namespace prjDownLoad
{
class Program
{
static void Main(string[] args)
{
Thread t = new Thread(new ThreadStart(Down));
t.Start();
}
static void Down()
{
DownloadUtil du = new DownloadUtil();
//订阅事件
du.DownloadChunkCompleted += new DownloadChunkCompletedHandler(du_DownloadChunkCompleted);
du.DownloadProgress += new DownloadProgressHandler(du_DownloadProgress);
du.DownloadCompleted += new DownloadCompletedHandler(du_DownloadCompleted);
//多线程
byte[] bs = du.DownloadData("http://down.360safe.com/setup.exe");
////单线程
//byte[] bs = du.DownloadData("http://blog.sina.com.cn/dalishuishou");
//方法1:使用DownloadData返回的内容。
FileStream fs = new FileStream("c:\\ee.pptx", FileMode.Create, FileAccess.Write);
fs.Write(bs, 0, bs.Length);
fs.Flush();
fs.Close();
}
/// <summary>
/// 下载完成事件
/// </summary>
static void du_DownloadCompleted(byte[] bs, string extensionFileName)
{
//方法2:在下载完成事件中处理。
FileStream fs = new FileStream("c:\\xx.pptx", FileMode.Create, FileAccess.Write);
fs.Write(bs, 0, bs.Length);
fs.Flush();
fs.Close();
Console.WriteLine("全部下载完成。");
}
/// <summary>
/// 下载过程事件处理过程
/// </summary>
/// <param name="bs"></param>
static void du_DownloadProgress(DownloadChunk dc)
{
Console.WriteLine("线程{0}下载了{1}字节",dc.Number,dc.Content.Length);
}
/// <summary>
/// 区块下载完成事件处理过程
/// </summary>
static void du_DownloadChunkCompleted(DownloadChunk dc)
{
Console.WriteLine("第{0}块下载完成,数据量:{1}",dc.Number,dc.Content.Length);
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace prjDownLoad
{
/// <summary>
/// 下载的数据块
/// </summary>
[Serializable]
public class DownloadChunk
{
//临时存储的集合
List<byte> content = new List<byte>();
/// <summary>
/// 整个块的内容
/// </summary>
public byte[] Content
{
get { return content.ToArray(); }
}
/// <summary>
/// 向块中添加内容
/// </summary>
/// <param name="bs"></param>
public void AddContent(byte[] bs)
{
content.AddRange(bs);
}
int from;
/// <summary>
/// 开始位置
/// </summary>
public int From
{
get { return from; }
set { from = value; }
}
int to;
/// <summary>
/// 结束位置
/// </summary>
public int To
{
get { return to; }
set { to = value; }
}
int number;
/// <summary>
/// 块编号
/// </summary>
public int Number
{
get { return number; }
set { number = value; }
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace prjDownLoad
{
/// <summary>
/// 区块下载完成委托
/// </summary>
/// <param name="dc">下载的区块</param>
public delegate void DownloadChunkCompletedHandler(DownloadChunk dc);
}
using System;
using System.Collections.Generic;
using System.Text;
namespace prjDownLoad
{
/// <summary>
/// 下载全部完成委托
/// </summary>
/// <param name="bs">完成的byte数组</param>
/// <param name="extensionFileName">后缀名</param>
public delegate void DownloadCompletedHandler(byte[] bs,string extensionFileName);
}
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net;
namespace prjDownLoad
{
/// <summary>
/// 下载信息实体类
/// </summary>
[Serializable]
public class DownloadInfo
{
DownloadChunk downloadChunk;
public DownloadChunk DownloadChunk
{
get { return downloadChunk; }
set { downloadChunk = value; }
}
WebRequest webRequest;
/// <summary>
/// 这个WebRequest中如果是分块下载
/// 那么在Range中要加上开始和结束位置
/// </summary>
public WebRequest WebRequest
{
get { return webRequest; }
set { webRequest = value; }
}
Stream readStream;
/// <summary>
/// 读取数据的流
/// </summary>
public Stream ReadStream
{
get { return readStream; }
set { readStream = value; }
}
byte[] buffer = new byte[1024];
/// <summary>
/// 缓冲字节数组,用来存储从流中读取的数据的容器
/// </summary>
public byte[] Buffer
{
get { return buffer; }
set { buffer = value; }
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace prjDownLoad
{
/// <summary>
/// 下载过程委托
/// </summary>
/// <param name="dc">下载的区块</param>
public delegate void DownloadProgressHandler(DownloadChunk dc);
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Net;
using System.IO;
namespace prjDownLoad
{
public class DownloadUtil
{
//固定为5个线程
const int ThreadSum = 5;
//线程数组
Thread[] ts=new Thread[ThreadSum];
DownloadInfo[] dis=new DownloadInfo[ThreadSum];
//已经完成的线程个数
int threadCount;
//多线程下载时的容器
byte[] allChunkContent;
//信号机
AutoResetEvent autoResetEvent=new AutoResetEvent(false);
/// <summary>
/// 区块下载完成事件
/// </summary>
public event DownloadChunkCompletedHandler DownloadChunkCompleted;
/// <summary>
/// 下载过程事件
/// </summary>
public event DownloadProgressHandler DownloadProgress;
/// <summary>
/// 某个任务完全下载完成。
/// </summary>
public event DownloadCompletedHandler DownloadCompleted;
//临时保存字节数组的集合(单线程下载时使用)
List<byte> bytes = new List<byte>();
//扩展名
string extensionFileName;
/// <summary>
/// 下载数据
/// </summary>
/// <param name="url">要下载的url</param>
/// <param name="fileName">要保存的文件名</param>
/// <returns>下载完成的byte数组</returns>
public byte[] DownloadData(string url)
{
long length=GetLength(url);
if (length==-1)
{
WebRequest wr = WebRequest.Create(url);
wr.BeginGetResponse(new AsyncCallback(GetResponseCallBack), wr);
autoResetEvent.WaitOne();
return bytes.ToArray();
}
else
{
//弄个大小相当的容器
allChunkContent=new byte[length];
//每块的大小
int blockSize =(int) (length / ThreadSum);
//剩下的大小
int surPlus=(int)(length%ThreadSum);
//开上几个线程,一块弄
for (int i = 0; i < ThreadSum; i++)
{
//老套路