[转]数据下载(二十一)
添加ftp支持,支持服务器登录。
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("ftp://down2.oamo.com:2121/05/31/聚生网管2.10.rar", "www.oamo.com", "www.oamo.com");
//方法1:使用DownloadData返回的内容。
FileStream fs = new FileStream("c:\\ee.zip", 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"+extensionFileName, 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
{
string userName;
string passWord;
//开始为1个线程
int ThreadSum = 1;
//线程数组
Thread[] ts;
DownloadInfo[] dis;
//已经完成的线程个数
int completedThreadCount = 0;
//多线程下载时的容器
byte[] allChunkContent = new byte[0];
//信号机
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;
//数据长度
long length;
/// <summary>
/// 下载数据
/// </summary>
/// <param name="url">要下载的url</param>
/// <param name="fileName">要保存的文件名</param>
/// <returns>下载完成的byte数组</returns>
public byte[] DownloadData(string url, string userName, string passWord)
{
url = System.Web.HttpUtility.UrlDecode(url);
this.userName = userName;
this.passWord = passWord;
length = GetLength(url);
//每块的大小
int blockSize = 0;
//剩下的大小
int surPlus = 0;
if (length != -1)
{
ThreadSum = 5;
//弄个大小相当的容器
allChunkContent = new byte[length];
//每块的大小
blockSize = (int)(length / ThreadSum);
//剩下的大小
surPlus = (int)(length % ThreadSum);
}
ts = new Thread[ThreadSum];
dis = new DownloadInfo[ThreadSum];
//开上几个线程,一块弄
for (int i = 0; i < ThreadSum; i++)
{
//老套路
WebRequest wr = WebRequest.Create(url);
if (userName != "" && passWord != "")
{
wr.Credentials = new NetworkCredential(userName, passWord);
}
//弄一个DownloadInfo
dis[i] = new DownloadInfo();
DownloadInfo di = dis[i];
//再弄一个DownloadChunk
DownloadChunk dc = new DownloadChunk();
di.DownloadChunk = dc;
//每块的起始位置
di.DownloadChunk.From = i * blockSize;
//每块的结束位置(最后一块要加上剩下的大小)
di.DownloadChunk.To = (int)(i == ThreadSum - 1 ? (i + 1) * blockSize + surPlus : (i + 1) * blockSize);
//给每个块编号
di.DownloadChunk.Number = i + 1;
//向请求中添加获取的范围(Content-Range)
//如果length为-1,那么意味着,不能用分块的方式下载。
Uri uri = new Uri(url);
if (uri.Scheme == Uri.UriSchemeHttp)
{
if (length != -1)
{
//新玩意:把WebRequest变成HttpWebRequest
//目的在于向请求头里面添加Content-Range
HttpWebRequest hwr = (HttpWebRequest)wr;
hwr.AddRange(di.DownloadChunk.From, di.DownloadChunk.To);
}
}
else
{
if (length != -1)
{
//新玩意:把WebRequest变成HttpWebRequest
//目的在于向请求头里面添加Content-Range
FtpWebRequest hwr = (FtpWebRequest)wr;
hwr.Method = WebRequestMethods.Ftp.DownloadFile;
//hwr.AddRange(di.DownloadChunk.From, di.DownloadChunk.To);
}
}
//塞进去
di.WebRequest = wr;
//实例化线程
//ts[i] = new Thread(new ParameterizedThreadStart(DownloadByChunk));
//也可以考虑将执行的内容加入线程池中。
ThreadPool.QueueUserWorkItem(new WaitCallback(DownloadByChunk), di);
}
如果上面没加入线程池,那么在这里启动线程
//for (int i = 0; i < ThreadSum; i++)
//{
// ts[i].Start(dis[i]);
//}
//还是等着呗
autoResetEvent.WaitOne();
return allChunkContent;
}
public byte[] DownloadData(string url)
{
return DownloadData(url, "", "");
}
/// <summary>
/// 就是把单线程处理部分的内容抄了一个过来。
/// </summary>
/// <param name="obj"></param>
private void DownloadByChunk(object obj)
{
DownloadInfo di = obj as DownloadInfo;
di.WebRequest.BeginGetResponse(new AsyncCallback(GetResponseCallBackByChunk), di);
}
/// <summary>
/// 当有回应对象时调用这个方法来处理(多线程)。
/// </summary>
/// <param name="result"></param>
void GetResponseCallBackByChunk(IAsyncResult result)
{
DownloadInfo di = result.AsyncState as DownloadInfo;
WebRequest wr = di.WebRequest;
WebResponse wsp = wr.EndGetResponse(result);
Stream st = wsp.GetResponseStream();
di.ReadStream = st;
st.BeginRead(di.Buffer, 0, di.Buffer.Length, new AsyncCallback(ReadCallBackByChunk), di);
}
/// <summary>
/// 一次读取完成后调用的方法(多线程)
/// </summary>
/// <param name="result"></param>
void ReadCallBackByChunk(IAsyncResult result)
{
DownloadInfo di = result.AsyncState as DownloadInfo;
int x = di.ReadStream.EndRead(result);
if (x > 0)
{
byte[] bs = SubBytes(di.Buffer, x);
//回来的数据先放到块中
di.DownloadChunk.AddContent(bs);
if (DownloadProgress != null)
{
DownloadProgress(di.DownloadChunk);
}
di.ReadStream.BeginRead(di.Buffer, 0, di.Buffer.Length, new AsyncCallback(ReadCallBackByChunk), di);
}
else
{
di.ReadStream.Close();
if (DownloadChunkCompleted != null)
{
DownloadChunkCompleted(di.DownloadChunk);
}
//某个块中的数据全部回来了,再加入容器中
if (length != -1)
{
//如果是多线程
Array.Copy(di.DownloadChunk.Content, 0, allChunkContent, di.DownloadChunk.From, di.DownloadChunk.Content.Length);
}
else
{
//如果是单线程。
allChunkContent = di.DownloadChunk.Content;
}
//完成的线程计数加一
completedThreadCount++;
//如果所有的线程都完了,才发信号,一个线程完了,不发信号
if (completedThreadCount == ThreadSum)
{
if (DownloadCompleted != null)
{
DownloadCompleted(allChunkContent, extensionFileName);
}
autoResetEvent.Set();
}
}
}
/// <summary>
/// 截取byte数组中的内容
/// </summary>
/// <param name="bs">源数组</param>
/// <param name="length">要截取的长度</param>
/// <returns>截取的结果数组</returns>
byte[] SubBytes(byte[] bs, int length)
{
byte[] temp = new byte[length];
Array.Copy(bs, 0, temp, 0, length);
return temp;
}
/// <summary>
/// 获取要下载的数据的长度
/// 如果为-1,那么不能分块下载
/// </summary>
/// <param name="url">要下载的Url</param>
/// <returns>内容的长度</returns>
long GetLength(string url)
{
url = System.Web.HttpUtility.UrlDecode(url);
WebRequest wr = WebRequest.Create(url);
if (userName != "" && passWord != "")
{
wr.Credentials = new NetworkCredential(userName, passWord);
}
WebResponse wsp = wr.GetResponse();
Uri uri = new Uri(url);
long length = wsp.ContentLength;
string s = wsp.ResponseUri.ToString();
int pointIndex = s.LastIndexOf(".");
if (pointIndex != -1)
{
extensionFileName = s.Substring(pointIndex);
}
else
{
extensionFileName = "";
}
wr.Abort();
wsp.Close();
return length;
}
}
}
转摘自:http://blog.sina.com.cn/s/blog_49458c270100ipvu.html
转载于:https://www.cnblogs.com/hxworm/articles/1968499.html
[转]数据下载(二十一)相关推荐
- 使用redis-shake工具迁移云Redis数据(二十一)
文章目录 1.在ECS服务器中部署相同版本的Redis 2.安装redis-shake工具 3.redis-shake配置文件 .4.将云Redis数据迁移至ECS的Redis中 5.检查数据的准确率 ...
- MODIS数据下载、拼接、转tif
modis数据的优势在于时间序列长,产品种类多. modis数据下载下来是hdf格式,且一份数据由很多瓦片数据组成,需要进行拼接.投影,转tif等操作 刚开始研究了好久使用MRT来对modis的hdf ...
- OSM道路数据下载与处理
OSM即是OpenStreetMap,是一个志愿者地理信息系统,人们在上面收集数据,下载数据. 文章目录 一.OSM数据的下载 1.OSM的注册 2.选择数据下载 二.OSM数据的转换 三 .数据的解 ...
- GISTEMP全球表面温度数据下载及处理
文章目录 前言 一.数据下载 二.数据处理步骤 1.数据读取 2.计算温度异常变化速率和区域平均值 3.实例展示 总结 前言 GISTEMP全拼为GISS Surface Temperature An ...
- android学习(二十一) 下载数据减少电池损耗
高效的网络访问(优化下载) 使用无线网络下载数据是你的应用消耗电池潜在的重要原因之一.为了降低和网络有关的activity连接导致的电池消耗.你理解你的连接模型怎样影响无线硬件这是很关键的. 下面将介 ...
- 某云数据中心网络解决方案(分享二十一)
某云数据中心网络解决方案(分享二十一) 参考文章: (1)某云数据中心网络解决方案(分享二十一) (2)https://www.cnblogs.com/zywu-king/p/8284189.html ...
- FreeSql (二十一)查询返回数据
FreeSql 采用 ExpressionTree 优化读取速读,如果懂技术的你一定知道 .NETCore 技术下除了原生代码,最快就是 Emit 和 ExpressionTree. 项目在初期使用的 ...
- 数据科学和人工智能技术笔记 二十一、统计学
二十一.统计学 作者:Chris Albon 译者:飞龙 协议:CC BY-NC-SA 4.0 贝塞尔校正 贝塞尔的校正是我们在样本方差和样本标准差的计算中使用 n−1n-1n−1 而不是 nnn 的 ...
- 二十一世纪最性感的职业:数据科学家
性感事物方面的权威<哈佛商业评论>宣布,"数据科学家"是二十一世纪最性感的职业.所谓性感,既代表着难以名状的诱惑,又说明了大家都不知道它干的是什么. 不管老板懂不懂数据 ...
- VUE学习(二十一)、Vuex(getters、mapState与mapGetters、mapMutations与mapActions、多组件共享数据、模块化编码)
VUE学习(二十一).Vuex(getters.mapState与mapGetters.mapMutations与mapActions.多组件共享数据.模块化编码) 一.Vuex普通实现求和案例 演示 ...
最新文章
- mysql数据库应用与开发姜桂洪 课后答案_一站式打卡“云原生”时代的高效开发...
- arm中断保护和恢复_浅谈ARM处理器的七种异常处理
- C和C++结构体区别
- django 允许跨域请求
- C++编译器默默编写并调用哪些函数
- RESTful API 设计思考
- keras + tensorflow —— 训练参数数目的计算
- python生成wps文件_使用Python操作XLS文件(wps中叫et)
- Vagrant:将装在C盘的虚拟机移动到别的目录
- 极限学习机和支持向量机_极限学习机的发展
- Java 代码生成器(CURD CRUD)
- 企业微信工具栏获取外部联系人unionid
- 国产操作系统之优麒麟安装
- sudo rosdep init 出现 ERROR: cannot download default sources list from:错误解决方法
- MySQL查询效率问题
- 利用openpyxl在Excel文件中批量复制模板表格
- 我在Facebook工作的十大经验分享
- 20个免费论文下载入口_含免费知网、万方、维普帐号
- mac的angular/cli安装及踩坑记录
- ATT加入Verizon与KT的合作圈,共同开发SDN/NFV/5G