一步一步编写FTP 文件下载类库(附源码)
1.引言
实现一个FTP 文件的下载功能。
2.初步构想
a)采用类库的方式实现FTP 文件的下载,在界面层实现类库的调用。
b)在文件下载的开始或结束能够反馈当前下载文件名、下载文件大小以及下载文件耗时等信息。
c)在文件下载的过程中能够实现文件下载进度显示功能。
3.FTP 类库实现
第一步:创建工程
创建命名为LibDldFile类库工程。
第二步:
在工程中建立IDldFile.cs 接口文件和FtpDldFile.cs 文件
定义文件下载接口


interface IDldFile
{
/// <summary>
/// 下载文件列表
/// </summary>
List<string> DldFilePathList { get;set;}
/// <summary>
/// 下载文件
/// </summary>
/// <returns></returns>
void Download();
}
第三步:初步实现FTP 下载功能
下面的FTPDldFile 类能够初步实现FTP 文件的下载。


public class FtpDldFile : IDldFile
{
private string _ftpLoginUser = string.Empty;
private string _ftpLoginPwd = string.Empty;
private string _dldFileSaveDir = string.Empty;
private List<string> _dldFileList = null;
private UInt32 _ftpDldSize = 1024;
/// <summary>
/// 创建FTP 下载对象(文件保存路径默认为当前程序启动路径)
/// </summary>
/// <param name="dldFileList">下载文件路径列表</param>
/// <param name="ftpLoginUser">FTP 登录用户</param>
/// <param name="ftpLoginPwd">FTP 登录密码</param>
public FtpDldFile(List<string> dldFileList, string ftpLoginUser, string ftpLoginPwd)
{
_dldFileList = dldFileList;
_ftpLoginPwd = ftpLoginPwd;
_ftpLoginUser = ftpLoginUser;
}
/// <summary>
/// 创建FTP 下载对象
/// </summary>
/// <param name="dldFileList">下载文件路径列表</param>
/// <param name="ftpLoginUser">FTP 登录用户</param>
/// <param name="ftpLoginPwd">FTP 登录密码</param>
/// <param name="dldFileSaveDir">下载文件保存路径</param>
public FtpDldFile(List<string> dldFileList, string ftpLoginUser, string ftpLoginPwd, string dldFileSaveDir)
{
_dldFileList = dldFileList;
_ftpLoginPwd = ftpLoginPwd;
_ftpLoginUser = ftpLoginUser;
_dldFileSaveDir = dldFileSaveDir;
}
/// <summary>
/// 下载文件保存路径
/// </summary>
public string DldFileSaveDir
{
get
{
if (_dldFileSaveDir == string.Empty)
_dldFileSaveDir = AppDomain.CurrentDomain.BaseDirectory;
//确保最后位为\
if (_dldFileSaveDir.Substring(_dldFileSaveDir.Length - 1) != @"\")
_dldFileSaveDir += "\\";
return _dldFileSaveDir;
}
set
{
_dldFileSaveDir = value;
}
}
/// <summary>
/// FTP 登录用户
/// </summary>
public string FtpLoginUser
{
get
{
if (_ftpLoginUser == string.Empty)
throw new Exception("The Ftp LoginUser is null");
return _ftpLoginUser;
}
set
{
_ftpLoginUser = value;
}
}
/// <summary>
/// FTP 登录密码
/// </summary>
public string FtpLoginPwd
{
get
{
if (_ftpLoginPwd == string.Empty)
throw new Exception("The Ftp LoginPwd is null");
return _ftpLoginPwd;
}
set
{
_ftpLoginPwd = value;
}
}
/// <summary>
/// 下载FTP 文件每次读取大小
/// </summary>
public UInt32 FtpDldSize
{
get
{
return _ftpDldSize;
}
set
{
_ftpDldSize = value;
}
}
#region IDldFile 成员
public List<string> DldFilePathList
{
get
{
if (_dldFileList == null)
_dldFileList = new List<string>();
return _dldFileList;
}
set
{
_dldFileList = value;
}
}
/// <summary>
/// 将指定的FTP 路径中目录路径和文件名称分离,获取文件名称
/// </summary>
/// <param name="ftpPath"></param>
/// <returns></returns>
public static string ConvertPathToFileName(string ftpPath)
{
string[] strArray = ftpPath.Split(new char[] { '/' });
return strArray[strArray.Length - 1];
}
public void Download()
{
//_dldFileList = new List<string>();
//_dldFileList.Add(@"ftp://192.168.0.21/incoming/1.txt");
//_ftpLoginPwd = "IECAS12345678";
//_ftpLoginUser = "xiangwei";
string curFileName = string.Empty;
try
{
FtpWebRequest request;
FtpWebResponse response;
foreach (string strFile in DldFilePathList)
{
curFileName = ConvertPathToFileName(strFile);
//校验文件是否存在,如果存在给出提示用户是否覆盖
if (System.IO.File.Exists(DldFileSaveDir + curFileName))
{
//通过委托获取用户是否同意覆盖
if (!EIsReplace(strFile))
{
continue;
}
}
request = (FtpWebRequest)WebRequest.Create(strFile);
request.KeepAlive = false;
request.Credentials = new NetworkCredential(_ftpLoginUser, _ftpLoginPwd);
using (response = (FtpWebResponse)request.GetResponse())
{
Stream data = response.GetResponseStream();
//文件大小
long fileLength = response.ContentLength;
//文件输出路径
string targetPath = DldFileSaveDir + curFileName;
//每次下载文件大小
byte[] byteBuffer = new byte[_ftpDldSize];
//当前已下载文件大小
long currentDldBytes = 0;
//当前已下载文件百分比
double currentPercentage = 0;
using (FileStream output = new FileStream(targetPath, FileMode.OpenOrCreate))
{
int bytesRead = 0;
do
{
//上报下载文件百分比
bytesRead = data.Read(byteBuffer, 0, byteBuffer.Length);
if (bytesRead > 0)
{
output.Write(byteBuffer, 0, bytesRead);
}
currentDldBytes += bytesRead;
currentPercentage = ((double)currentDldBytes / (double)fileLength) * 100;
}
while (bytesRead > 0);
}
}
}
}
catch (WebException e)
{
throw new WebException("Download " + curFileName + " error has occored!The exception message is " + e.Message);
}
}
#endregion
}
第四步:
实现下载文件过程中信息反馈(包括下载文件信息、时间和百分比)
首先,在接口中定义事件和委托:


/// <summary>
/// 委托,用于标识提示用户是否需要覆盖当前文件
/// </summary>
/// <param name="fileName">覆盖文件名称</param>
/// <returns></returns>
public delegate bool DelegateIsReplace(string fileName);
/// <summary>
/// 委托,用于标识当前文件下载百分比
/// </summary>
/// <param name="dldPercentage">当前文件下载百分比</param>
public delegate void DelegateDldPercentage(double dldPercentage);
/// <summary>
/// 委托,用于标识下载文件信息
/// </summary>
/// <param name="message"></param>
public delegate void DelegateDldMessage(string message);
interface IDldFile
{
List<string> DldFilePathList { get;set;}
/// <summary>
/// 下载文件
/// </summary>
/// <returns></returns>
void Download();
/// <summary>
/// 事件,用于提示用户是否覆盖已经存在文件
/// </summary>
event DelegateIsReplace EIsReplace;
/// <summary>
/// 当前下载文件百分比
/// </summary>
event DelegateDldPercentage EDldPercentage;
/// <summary>
/// 下载文件信息
/// </summary>
event DelegateDldMessage EDldMessage;
}
原来的下载类再次实现该接口信息后,并且在下载Download 方法中调用事件:


public void Download()
{
//_dldFileList = new List<string>();
//_dldFileList.Add(@"ftp://192.168.0.21/incoming/1.txt");
//_ftpLoginPwd = "IECAS12345678";
//_ftpLoginUser = "xiangwei";
string curFileName = string.Empty;
try
{
FtpWebRequest request;
FtpWebResponse response;
foreach (string strFile in DldFilePathList)
{
curFileName = ConvertPathToFileName(strFile);
//校验文件是否存在,如果存在给出提示用户是否覆盖
if (System.IO.File.Exists(DldFileSaveDir + curFileName))
{
//通过委托获取用户是否同意覆盖
if (!EIsReplace(strFile))
{
continue;
}
}
request = (FtpWebRequest)WebRequest.Create(strFile);
request.KeepAlive = false;
request.Credentials = new NetworkCredential(_ftpLoginUser, _ftpLoginPwd);
using (response = (FtpWebResponse)request.GetResponse())
{
Stream data = response.GetResponseStream();
//文件大小
long fileLength = response.ContentLength;
//文件输出路径
string targetPath = DldFileSaveDir + curFileName;
//每次下载文件大小
byte[] byteBuffer = new byte[_ftpDldSize];
//当前已下载文件大小
long currentDldBytes = 0;
//当前已下载文件百分比
double currentPercentage = 0;
//开始下载文件时间
DateTime startTime = DateTime.Now;
TimeSpan timeSpan;
using (FileStream output = new FileStream(targetPath, FileMode.OpenOrCreate))
{
int bytesRead = 0;
//上报开始下载文件信息
EDldMessage("开始下载文件:" + curFileName + " 文件大小:" + fileLength );
do
{
//上报下载文件百分比
EDldPercentage(currentPercentage);
bytesRead = data.Read(byteBuffer, 0, byteBuffer.Length);
if (bytesRead > 0)
{
output.Write(byteBuffer, 0, bytesRead);
}
currentDldBytes += bytesRead;
currentPercentage = ((double)currentDldBytes / (double)fileLength) * 100;
}
while (bytesRead > 0);
timeSpan = DateTime.Now - startTime;
EDldMessage("下载" + curFileName + "完成,耗时:" + timeSpan.Minutes.ToString() + " 分 " + timeSpan.Seconds + " 秒 " + timeSpan.Milliseconds + "毫秒");
}
}
}
}
catch (WebException e)
{
throw new WebException("Download " + curFileName + " error has occored!The exception message is " + e.Message);
}
}
第五步:实现界面层
好了,一个简单的FTP 下载类库已经编写好了,我们再来写一个界面层调用程序来实现这个类库的调用吧.
( 不知道是不是博客园的问题,我这边上传JPG或者GIF文件不能成功,本来想截个图的。)
界面中包括保存文件路径和下载按钮,和反馈信息显示栏及进度条。
调用类库代码:


private void btnSure_Click(object sender, EventArgs e)
{
FtpDldFile ftpDldFile = new FtpDldFile(DldFileList, _ftpLoginUser, _ftpLoginPwd, this.textBox1.Text);
ftpDldFile.EIsReplace += new DelegateIsReplace(ftpDldFile_EIsReplace);
ftpDldFile.EDldMessage += new DelegateDldMessage(ftpDldFile_EDldMessage);
ftpDldFile.EDldPercentage += new DelegateDldPercentage(ftpDldFile_EDldPercentage);
this.btnSure.Enabled = false;
this.btnClose.Enabled = false;
ftpDldFile.Download();
this.btnSure.Enabled = true;
this.btnClose.Enabled = true;
}
/// <summary>
/// 进度条
/// </summary>
/// <param name="dldPercentage"></param>
void ftpDldFile_EDldPercentage(double dldPercentage)
{
this.toolStripProgressBar1.Value = (Int32)dldPercentage;
Application.DoEvents();
}
/// <summary>
/// 反馈信息
/// </summary>
/// <param name="message"></param>
void ftpDldFile_EDldMessage(string message)
{
this.toolStripStatusLabel1.Text = message;
Application.DoEvents();
}
/// <summary>
/// 是否覆盖原来文件
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
bool ftpDldFile_EIsReplace(string fileName)
{
if (MessageBox.Show("当前" + fileName + "已经存在,是否覆盖?", "确认信息", MessageBoxButtons.YesNo) == DialogResult.Yes)
return true;
else
return false;
}
我这里只是一步一步介绍了编写一个简单FTP 文件下载类库的过程,希望能够对一部分人有帮助.其后附源码:
作者:心不蒙尘
出处:http://www.cnblogs.com/stan0714/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
该文章也同时发布在我的独立博客中-心不蒙尘。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述