由于研究Winform项目的版本自动检测更新,需要用到Ftp下载更新包文件。
特写出这个小Demo.
我的Ftp是本地用IIS搭建的FTP服务器,下载过一个1.8G的视频文件,亲测有效。
注意点:
- Ftp类编写需要参考FTP的帮助文档
- 同步更新下载进度状态、下载完成状态的方法:将更新事件的方法绑定到Ftp封装类公布的事件中。
- 多线程控制窗体控件的时候不能直接对控件进行赋值等操作,需要将操控UI的代码写在一个委托当中,然后用This.Invoke(操控控件委托)。
运行效果如图:
内容比较多,我会上传Demo附件
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Framework;
namespace DemoFtp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
txtLocalPath.Text = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
}
/// <summary>
/// 主线程下载
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnDownLoad_Click(object sender, EventArgs e)
{
FtpClient ftpClient = new FtpClient("192.168.0.104","/","FtpUser","Chendong144216,");
string remoteFilePath = txtRemotePath.Text;
string fileName = Path.GetFileName(remoteFilePath);
string localFilePath = txtLocalPath.Text + "\\" + fileName;
ftpClient.DownLoadFile(remoteFilePath, localFilePath);
}
/// <summary>
/// 异步下载
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnDownloadAsync_Click(object sender, EventArgs e)
{
FtpClient ftpClient = new FtpClient("192.168.0.104", "/", "FtpUser", "Chendong144216,");
string remoteFilePath = txtRemotePath.Text;
string fileName = Path.GetFileName(remoteFilePath);
string localFilePath = txtLocalPath.Text + "\\" + fileName;
ftpClient.DownloadProgressChanged += DownloadProgressChanged;
ftpClient.DownloadDataCompleted += DownLoadDataComplete;
Task<long> task = ftpClient.DownLoadFileAsync(remoteFilePath, txtLocalPath.Text, fileName);
}
/// <summary>
/// 传入委托的方法,用于设置完成状态
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void DownLoadDataComplete(object sender, FtpClient.UpDownLoadCompletedArgs e)
{
Action action = ()=>
{
pgb.Value = 100;
lblProgressValue.Text = "下载完毕";
};
this.Invoke(action);
}
/// <summary>
/// 传入委托的方法,用于设置下载进度状态
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void DownloadProgressChanged(object sender, FtpClient.UpDownLoadProcessArgs e)
{
Action<int> action = v =>
{
pgb.Value = v;
lblProgressValue.Text = $"下载进度 {v}%";
};
this.Invoke(action, e.ProgressPercentage);
}
}
}
Ftp封装类
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Framework
{
/// <summary>
/// 文件结构信息
/// </summary>
public struct FtpFileStruct
{
/// <summary>
///
/// </summary>
public string Flags;
/// <summary>
/// 拥有者
/// </summary>
public string Owner;
/// <summary>
/// 文件组
/// </summary>
public string Group;
/// <summary>
/// 是否目录
/// </summary>
public bool IsDirectory;
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreateTime;
/// <summary>
/// 文件名
/// </summary>
public string Name;
/// <summary>
/// 文件长度
/// </summary>
public double Length;
}
/// <summary>
/// 文件列表类型
/// </summary>
public enum FtpFileListStyle
{
UnixStyle, //UNIX类型
WindowsStyle, //WINDOWS
Unknown //未知
}
/// <summary>
/// 传输模式:二进制类型、ASCII类型
/// </summary>
public enum FtpTransferType {
Binary, ASCII };
/// <summary>
/// Ftp上传下载
/// </summary>
public class FtpClient : IDisposable //Ftp上传下载
{
#region Private Fields
/// <summary>
/// 用户名
/// </summary>
private string _UserName;
/// <summary>
/// 密码
/// </summary>
private string _Password;
/// <summary>
/// 初始创建Ftp类时候制定的根目录
/// </summary>
private string _RootDirectory;
/// <summary>
/// 工作目录
/// </summary>
private string _WorkDirectory;
/// <summary>
/// 服务器返回的应答信息(包含应答码)
/// </summary>
private string ReplyMessage {
get; set; }
/// <summary>
/// 服务器返回的应答码
/// </summary>
private int ReplyCode {
get; set; }
/// <summary>
/// 进行控制连接的socket
/// </summary>
private Socket _SocketControl;
/// <summary>
/// 传输模式
/// </summary>
private FtpTransferType _TransferType = Framework.FtpTransferType.ASCII;
/// <summary>
/// 接收和发送数据的缓冲区
/// </summary>
private Byte[] _Buffer = new Byte[BUFFER_SIZE];
/// <summary>
/// 当前尝试连接ID,用于报错
/// </summary>
IPAddress _IPAddress;
int tryConnectTimes = 0;
#endregion
#region Property
/// <summary>
/// FTP服务器IP地址
/// </summary>
public string Host {
get; set; }
/// <summary>
/// FTP服务器端口
/// </summary>
public int Port {
get; set; }
/// <summary>
/// 目录
/// </summary>
public string WorkDirectory
{
get
{
if (!string.IsNullOrEmpty(_WorkDirectory)) return _WorkDirectory;
if (!IsConnected) Connect();
SetCurrentWorkDirectory();
return _WorkDirectory;
}
set
{
if (string.IsNullOrEmpty(_RootDirectory))//第一次设置Directory的时候,定RootDirectory
_RootDirectory = value;
if (_WorkDirectory != value)
{
_WorkDirectory = value;
if (IsConnected)//如果正在连接,则更换当前目录
ChangeWorkDirectory(_WorkDirectory);
}
}
}
/// <summary>
/// 在不知道当前路径的情况下提取并设置对应字段
/// </summary>
private void SetCurrentWorkDirectory()
{
SendCommand("PWD ");
if (!(ReplyCode == 257)) throw new IOException(ReplyMessage.Substring(4));//return strPath;
string dir = ReplyMessage.Substring(5);
_WorkDirectory = dir.Substring(0, dir.IndexOf("\""));
}
/// <summary>
/// 异步事件的间隔时间,毫秒
/// </summary>
public int AsyncTriggerInterval {
get; set; } = 200;
/// <summary>
/// 缓冲大小
/// </summary>
public static int BUFFER_SIZE {
get; set; } = 1024 * 8;
/// <summary>
/// 编码方式
/// </summary>
public Encoding Encoder {
get; set; } = Encoding.Default;
/// <summary>
/// 代理
/// </summary>
public WebProxy WebProxy {
get; }
/// <summary>
/// 是否登录
/// </summary>
public bool IsConnected {
get; private set; }
/// <summary>
/// 获得传输模式
/// </summary>
/// <returns>传输模式</returns>
public FtpTransferType TransferType
{
get {
return _TransferType; }
set
{
if (value == _TransferType) return; //如果TransferType已经一样则不重复发送
if (value == FtpTransferType.Binary)
SendCommand("TYPE I");//binary类型传输
else
SendCommand("TYPE A");//ASCII类型传输
if (ReplyCode != 200)
throw new IOException(ReplyMessage.Substring(4));
else
_TransferType = value;
}
}
#endregion
#region EventArgs
/// <summary>
/// 上传下载进度
/// </summary>
public class UpDownLoadProcessArgs : EventArgs
{
private long _TotalBytes;
private long _CurrentBytes;
public UpDownLoadProcessArgs(long currentBytes, long totalBytes)
{
_CurrentBytes = currentBytes;
_TotalBytes = totalBytes;
}
/// <summary>
/// 完成进度百分比
/// </summary>
public int ProgressPercentage
{
get {
return (int)(((double)_CurrentBytes / (double)_TotalBytes) * 100); }
}
/// <summary>
/// 总字节数
/// </summary>
public long TotalBytes
{
get {
return _TotalBytes; }
}
/// <summary>
/// 当前字节数
/// </summary>
public long CurrentBytes
{
get {
return _CurrentBytes; }
}
}
/// <summary>
/// 上传下载完成事件
/// </summary>
public class UpDownLoadCompletedArgs : EventArgs
{
private readonly long _TotalBytes;
private readonly long _CurrentBytes;
public UpDownLoadCompletedArgs(long curBytes, long totalBytes)
{
_CurrentBytes = curBytes;
_TotalBytes = totalBytes;
}
/// <summary>
/// 进度百分比
/// </summary>
public int ProgressPercentage
{
get {
return (int)(((double)_CurrentBytes / (double)_TotalBytes) * 100); }
}
/// <summary>
/// 是否完成
/// </summary>
public bool IsCompleted
{
get {
return _CurrentBytes >= _TotalBytes; }
}
/// <summary>
/// 总字节数
/// </summary>
public long TotalBytes
{
get {
return _TotalBytes; }
}
/// <summary>
/// 当前字节数
/// </summary>
public long CurrentBytes
{
get {
return _CurrentBytes; }
}
}
/// <summary>
/// 返回服务器特性
/// </summary>
/// <returns></returns>
public string Feature
{
get
{
SendCommand("FEAT");
return ReplyMessage;
}
}
#endregion
#region Deletegate
public delegate void FtpDownloadProgressChanged(object sender, UpDownLoadProcessArgs e);
public delegate void FtpDownloadDataCompleted(object sender, UpDownLoadCompletedArgs e);
public delegate void FtpUploadProgressChanged(object sender, UpDownLoadProcessArgs e);
public delegate void FtpUploadFileCompleted(object sender, UpDownLoadCompletedArgs e);
#endregion
#region Event
/// <summary>
/// 异步下载进度发生改变触发的事件
/// </summary>
public event FtpDownloadProgressChanged DownloadProgressChanged;
/// <summary>
/// 异步下载文件完成之后触发的事件
/// </summary>
public event FtpDownloadDataCompleted DownloadDataCompleted;
/// <summary>
/// 异步上传进度发生改变触发的事件
/// </summary>
public event FtpUploadProgressChanged UploadProgressChanged;
/// <summary>
/// 异步上传文件完成之后触发的事件
/// </summary>
public</