网上没找到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;
类主体:
代码
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
}
测试代码:
代码
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 " ));