多线程下载(FtpWebRequest)
网上没找到FtpWebRequest多线程下载的资料,自己写了一个。但没达到预期效果,下面是测试结果:
//1线程下载133M 18秒
//5线程 下载133M 40秒
//单线程 下载133M 12秒
期望高手不吝赐教,下面是完整代码
首先命名空间
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Net;
using System.IO;
using System.Threading;
using System.Net;
类主体:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class MultiFtpService
{
#region 变量
private string _Server;//服务器地址
private string _UserName;//用户名
private string _Password;//密码
private int _Port;//端口
private long _FileSize;//文件大小
private string _FileUrl;//文件地址
private string _SavePath;//保存路经
private string _SaveFileName;//保存文件名
private string _SaveExtName;//保存文件扩展名
private int _ThreadNum;//线程数量
private short _ThreadCompleteNum;//线程完成数量
private bool _IsComplete = false;//是否完成
private volatile int _DownloadSize;//当前下载大小
private Thread[] _Thread;//线程数组
private List<string> _TempFiles = new List<string>();
private FtpWebRequest ftpRequest;
#endregion
#region 属性
public string Server
{
get { return _Server; }
set { _Server = value; }
}
public string UserName
{
get { return _UserName; }
set { _UserName = value; }
}
public string Password
{
get { return _Password; }
set { _Password = value; }
}
public int Port
{
get { return _Port; }
set { _Port = value; }
}
public long FileSize
{
get { return _FileSize; }
set { _FileSize = value; }
}
public string FileUrl
{
get { return _FileUrl; }
set { _FileUrl = value; }
}
public string SavePath
{
get { return _SavePath; }
set { _SavePath = value; }
}
public string SaveFileName
{
get { return _SaveFileName; }
set { _SaveFileName = value; }
}
public string SaveExtName
{
get { return _SaveExtName; }
set { _SaveExtName = value; }
}
public int ThreadNum
{
get { return _ThreadNum; }
set { _ThreadNum = value; }
}
public short ThreadCompleteNum
{
get { return _ThreadCompleteNum; }
set { _ThreadCompleteNum = value; }
}
public bool IsComplete
{
get { return _IsComplete; }
}
public int DownloadSize
{
get { return _DownloadSize; }
}
#endregion
#region Constructor
public MultiFtpService(string server, string username, string password, int threadNum)
: this(server, username, password, 21, threadNum, "", "")
{
}
public MultiFtpService(string server, string username, string password, int port,int threadNum)
: this(server, username, password, port, threadNum, "", "")
{
}
public MultiFtpService(string server, string username, string password, int threadNum, string fileUrl, string savePath)
: this(server, username, password, 21, threadNum, fileUrl, savePath)
{
}
public MultiFtpService(string server, string username, string password, int port,int threadNum, string fileUrl, string savePath)
{
_Server = server;
_UserName = username;
_Password = password;
_Port = port;
_ThreadNum = threadNum;
_FileUrl = fileUrl;
_SavePath = savePath;
_Thread = new Thread[_ThreadNum];
}
#endregion
#region Functions
public void Start()
{
FtpWebRequest ftpRequest = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + _Server + ":" + _Port + "/" + _FileUrl));
ftpRequest.Method = WebRequestMethods.Ftp.GetFileSize;
ftpRequest.KeepAlive = false;
ftpRequest.UseBinary = true;
ftpRequest.Credentials = new NetworkCredential(_UserName, _Password);
FtpWebResponse response = (FtpWebResponse)ftpRequest.GetResponse();
_FileSize = response.ContentLength;
int singelNum = (int)(_FileSize / _ThreadNum);//平均分配
int remainder = (int)(_FileSize % _ThreadNum);//获取剩余的
for (int i = 0; i < _ThreadNum; i++)
{
List<int> range = new List<int>();
range.Add(i * singelNum);
if (remainder != 0 && (_ThreadNum - 1) == i)//剩余的交给最后一个线程
range.Add(i * singelNum + singelNum + remainder - 1);
else
range.Add(i * singelNum + singelNum - 1);
_Thread[i] = new Thread(() => { Download(range[0], range[1]); });
_Thread[i].Name = string.Format("thread_{0}",i + 1);
_Thread[i].Start();
}
}
/// <summary>
/// 拆分分段下载
/// </summary>
/// <param name="from">开始</param>
/// <param name="to">结束</param>
private void Download(int from, int to)
{
string tmpFileBlock = string.Format(@"{0}\{1}_{2}.dat", _SavePath, _SaveFileName, Thread.CurrentThread.Name);
_TempFiles.Add(tmpFileBlock);
int count = 0;
int readCount = 0;
try
{
ftpRequest = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + _Server + ":" + _Port + "/" + _FileUrl));
//ftpRequest.ContentOffset = from;//设置文件的偏移量
ftpRequest.Method = WebRequestMethods.Ftp.DownloadFile;
ftpRequest.UseBinary = true;
ftpRequest.Credentials = new NetworkCredential(UserName, Password);
using (FileStream outputStream = new FileStream(tmpFileBlock, FileMode.Create))
using (FtpWebResponse response = (FtpWebResponse)ftpRequest.GetResponse())
using (Stream ftpStream = response.GetResponseStream())
{
int bufferSize = 81920;
byte[] buffer = new byte[bufferSize];
while ((readCount = ftpStream.Read(buffer, 0, bufferSize)) > 0)
{
count += readCount;
if (from<to && from + readCount >= to)
{
outputStream.Write(buffer, 0, to-from);
_DownloadSize += to - from;
break;
}
else if (from == count - readCount)
{
outputStream.Write(buffer, 0, readCount);
_DownloadSize += readCount;
from = count;
}
else if (count > from && from > count - readCount)
{
outputStream.Write(buffer, readCount - (count - from), count - from);
_DownloadSize += count - from;
from = count;
}
}
_ThreadCompleteNum++;
}
}
catch (Exception e)
{
throw e;
}
if (_ThreadCompleteNum == _ThreadNum)
{
Complete();
}
}
/// <summary>
/// 合并临时文件
/// </summary>
private void Complete()
{
Stream mergeFile = new FileStream(string.Format(@"{0}\{1}{2}",_SavePath,_SaveFileName,_SaveExtName), FileMode.Create);
BinaryWriter AddWriter = new BinaryWriter(mergeFile);
foreach (string file in _TempFiles)
{
using (FileStream fs = new FileStream(file, FileMode.Open))
using(BinaryReader tempReader = new BinaryReader(fs))
{
AddWriter.Write(tempReader.ReadBytes((int)fs.Length));
}
File.Delete(file);
}
AddWriter.Close();
_IsComplete = true;
}
#endregion
}
{
#region 变量
private string _Server;//服务器地址
private string _UserName;//用户名
private string _Password;//密码
private int _Port;//端口
private long _FileSize;//文件大小
private string _FileUrl;//文件地址
private string _SavePath;//保存路经
private string _SaveFileName;//保存文件名
private string _SaveExtName;//保存文件扩展名
private int _ThreadNum;//线程数量
private short _ThreadCompleteNum;//线程完成数量
private bool _IsComplete = false;//是否完成
private volatile int _DownloadSize;//当前下载大小
private Thread[] _Thread;//线程数组
private List<string> _TempFiles = new List<string>();
private FtpWebRequest ftpRequest;
#endregion
#region 属性
public string Server
{
get { return _Server; }
set { _Server = value; }
}
public string UserName
{
get { return _UserName; }
set { _UserName = value; }
}
public string Password
{
get { return _Password; }
set { _Password = value; }
}
public int Port
{
get { return _Port; }
set { _Port = value; }
}
public long FileSize
{
get { return _FileSize; }
set { _FileSize = value; }
}
public string FileUrl
{
get { return _FileUrl; }
set { _FileUrl = value; }
}
public string SavePath
{
get { return _SavePath; }
set { _SavePath = value; }
}
public string SaveFileName
{
get { return _SaveFileName; }
set { _SaveFileName = value; }
}
public string SaveExtName
{
get { return _SaveExtName; }
set { _SaveExtName = value; }
}
public int ThreadNum
{
get { return _ThreadNum; }
set { _ThreadNum = value; }
}
public short ThreadCompleteNum
{
get { return _ThreadCompleteNum; }
set { _ThreadCompleteNum = value; }
}
public bool IsComplete
{
get { return _IsComplete; }
}
public int DownloadSize
{
get { return _DownloadSize; }
}
#endregion
#region Constructor
public MultiFtpService(string server, string username, string password, int threadNum)
: this(server, username, password, 21, threadNum, "", "")
{
}
public MultiFtpService(string server, string username, string password, int port,int threadNum)
: this(server, username, password, port, threadNum, "", "")
{
}
public MultiFtpService(string server, string username, string password, int threadNum, string fileUrl, string savePath)
: this(server, username, password, 21, threadNum, fileUrl, savePath)
{
}
public MultiFtpService(string server, string username, string password, int port,int threadNum, string fileUrl, string savePath)
{
_Server = server;
_UserName = username;
_Password = password;
_Port = port;
_ThreadNum = threadNum;
_FileUrl = fileUrl;
_SavePath = savePath;
_Thread = new Thread[_ThreadNum];
}
#endregion
#region Functions
public void Start()
{
FtpWebRequest ftpRequest = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + _Server + ":" + _Port + "/" + _FileUrl));
ftpRequest.Method = WebRequestMethods.Ftp.GetFileSize;
ftpRequest.KeepAlive = false;
ftpRequest.UseBinary = true;
ftpRequest.Credentials = new NetworkCredential(_UserName, _Password);
FtpWebResponse response = (FtpWebResponse)ftpRequest.GetResponse();
_FileSize = response.ContentLength;
int singelNum = (int)(_FileSize / _ThreadNum);//平均分配
int remainder = (int)(_FileSize % _ThreadNum);//获取剩余的
for (int i = 0; i < _ThreadNum; i++)
{
List<int> range = new List<int>();
range.Add(i * singelNum);
if (remainder != 0 && (_ThreadNum - 1) == i)//剩余的交给最后一个线程
range.Add(i * singelNum + singelNum + remainder - 1);
else
range.Add(i * singelNum + singelNum - 1);
_Thread[i] = new Thread(() => { Download(range[0], range[1]); });
_Thread[i].Name = string.Format("thread_{0}",i + 1);
_Thread[i].Start();
}
}
/// <summary>
/// 拆分分段下载
/// </summary>
/// <param name="from">开始</param>
/// <param name="to">结束</param>
private void Download(int from, int to)
{
string tmpFileBlock = string.Format(@"{0}\{1}_{2}.dat", _SavePath, _SaveFileName, Thread.CurrentThread.Name);
_TempFiles.Add(tmpFileBlock);
int count = 0;
int readCount = 0;
try
{
ftpRequest = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + _Server + ":" + _Port + "/" + _FileUrl));
//ftpRequest.ContentOffset = from;//设置文件的偏移量
ftpRequest.Method = WebRequestMethods.Ftp.DownloadFile;
ftpRequest.UseBinary = true;
ftpRequest.Credentials = new NetworkCredential(UserName, Password);
using (FileStream outputStream = new FileStream(tmpFileBlock, FileMode.Create))
using (FtpWebResponse response = (FtpWebResponse)ftpRequest.GetResponse())
using (Stream ftpStream = response.GetResponseStream())
{
int bufferSize = 81920;
byte[] buffer = new byte[bufferSize];
while ((readCount = ftpStream.Read(buffer, 0, bufferSize)) > 0)
{
count += readCount;
if (from<to && from + readCount >= to)
{
outputStream.Write(buffer, 0, to-from);
_DownloadSize += to - from;
break;
}
else if (from == count - readCount)
{
outputStream.Write(buffer, 0, readCount);
_DownloadSize += readCount;
from = count;
}
else if (count > from && from > count - readCount)
{
outputStream.Write(buffer, readCount - (count - from), count - from);
_DownloadSize += count - from;
from = count;
}
}
_ThreadCompleteNum++;
}
}
catch (Exception e)
{
throw e;
}
if (_ThreadCompleteNum == _ThreadNum)
{
Complete();
}
}
/// <summary>
/// 合并临时文件
/// </summary>
private void Complete()
{
Stream mergeFile = new FileStream(string.Format(@"{0}\{1}{2}",_SavePath,_SaveFileName,_SaveExtName), FileMode.Create);
BinaryWriter AddWriter = new BinaryWriter(mergeFile);
foreach (string file in _TempFiles)
{
using (FileStream fs = new FileStream(file, FileMode.Open))
using(BinaryReader tempReader = new BinaryReader(fs))
{
AddWriter.Write(tempReader.ReadBytes((int)fs.Length));
}
File.Delete(file);
}
AddWriter.Close();
_IsComplete = true;
}
#endregion
}
测试代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
MultiFtpService multiFtp = new MultiFtpService("172.18.118.106", "ff", "ff",1);
string path = "10031544820/20100310/4014200";
DateTime dt = DateTime.Now;
string fileName = "CX.IMG";
//ftp.Download(path + "/" + fileName, pathdir + "/" + path + "/" + fileName, true);
multiFtp.FileUrl = path + "/" + fileName;
multiFtp.SavePath = pathdir + "/" + path;
multiFtp.SaveFileName = fileName.Substring(0, fileName.IndexOf('.'));
multiFtp.SaveExtName = fileName.Substring(fileName.IndexOf('.'));
multiFtp.Start();
while (!multiFtp.IsComplete)
{
System.Threading.Thread.Sleep(1);
}
MessageBox.Show("完成:前时间为" + dt.ToString("yyyy-MM-dd hh:mm:ss") + "\n" + "现在时间为" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"));
string path = "10031544820/20100310/4014200";
DateTime dt = DateTime.Now;
string fileName = "CX.IMG";
//ftp.Download(path + "/" + fileName, pathdir + "/" + path + "/" + fileName, true);
multiFtp.FileUrl = path + "/" + fileName;
multiFtp.SavePath = pathdir + "/" + path;
multiFtp.SaveFileName = fileName.Substring(0, fileName.IndexOf('.'));
multiFtp.SaveExtName = fileName.Substring(fileName.IndexOf('.'));
multiFtp.Start();
while (!multiFtp.IsComplete)
{
System.Threading.Thread.Sleep(1);
}
MessageBox.Show("完成:前时间为" + dt.ToString("yyyy-MM-dd hh:mm:ss") + "\n" + "现在时间为" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"));