ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

C# WinForm + FluentFTP 上位机文件回传实战:断点续传与进度回调

C# WinForm + FluentFTP 上位机文件回传实战:断点续传与进度回调 简介这是一份面向C#桌面开发者的FTP客户端实战示例基于WinForm与FluentFTP库实现文件上传下载功能适合正在学习.NET网络编程、需要快速搭建FTP工具或为项目集成FTP模块的初中级开发者参考。压缩包共62个文件约2.7MB以cs源码、dll依赖库、xml与config配置文件为主另含resx资源、ico图标、png图片及sln解决方案、csproj工程文件等完整保留了Visual Studio 2022下的工程结构与依赖包可直接打开编译运行。资源围绕FtpHelper封装、FtpElementControl控件与MainForm主界面展开展示了连接配置、上传下载调用与界面交互的典型写法便于读者理解FluentFTP在实际项目中的组织方式。目前已有613人学习下载可作为FTP功能开发的入门模板与排错参考。1. 从一次产线数据回传翻车说起这套 C# WinForm FluentFTP 实例到底能干什么去年帮一家做视觉检测的客户做上位机相机拍完图要定时往厂内 FTP 服务器回传我图省事用了System.Net.FtpWebRequest本地跑得好好的一上产线就间歇性超时日志里全是425 Cannot open data connection折腾两天才发现是被动模式和连接复用没处理好。后来换成 FluentFTP同样的网络环境代码量砍掉一半断点续传、进度回调、目录递归这些全是现成的。这份DemoFtp实例就是围绕这个场景拆出来的C# WinForm FluentFTP开发工具 VisualStudio2022框架 .Net Framework 4.8 及以上压缩包里带FtpHelper.cs封装、FtpElementControl自定义控件、MainForm主界面和packages.config依赖声明FluentFTP.45.1.0已经躺在 packages 目录里。它解决的不是「FTP 是什么」这种问题而是「WinForm 里怎么把上传下载做得能上产线、能看进度、能断点续传、出错能定位」。适合正在做 c#上位机、工控数据回传、WinForm 项目案例的从业者新手能照着把环境跑起来熟手能直接扒FtpHelper的封装思路。2. 环境搭建与 FluentFTP 依赖落地从 sln 到第一个连接2.1 为什么选 FluentFTP 而不是原生 FtpWebRequest原生FtpWebRequest不是不能用是坑太散。它把连接、命令、数据通道全揉在一个请求对象里被动模式要手动设UsePassive超时要自己算断点续传得自己拼REST命令异步支持也别扭。FluentFTP 把这些收敛成AsyncFtpClient旧版是FtpClient一个对象Connect、UploadFile、DownloadFile、GetListing都是同步异步双份进度事件Progress直接给百分比和字节数WinForm 里更新进度条不用自己算。这份实例用的是FluentFTP.45.1.0对应 .Net Framework 4.8packages.config里已经声明好不用去 NuGet 现搜。选它的核心理由就一条产线环境网络抖动多FluentFTP 的重连和超时参数是显式暴露的出问题能调原生那套只能靠猜。2.2 还原 sln 与确认依赖版本拿到DemoFtp.rar解压后目录结构是这样的DemoFtp.sln在根DemoFtp文件夹是主工程packages放依赖.vs是 VS 的隐藏缓存目录可以删。用 VS2022 打开 sln第一步不是急着 F5是先确认packages.config里的版本和DemoFtp.csproj的引用路径对得上。!-- packages.config 关键行确认 FluentFTP 版本 -- packages package idFluentFTP version45.1.0 targetFrameworknet48 / /packages!-- DemoFtp.csproj 里 HintPath 必须指向 packages 实际解压路径 -- Reference IncludeFluentFTP, Version45.1.0.0, Cultureneutral, processorArchitectureMSIL HintPath..\packages\FluentFTP.45.1.0\lib\net45\FluentFTP.dll/HintPath /Reference逻辑说明packages.config是 NuGet 旧式还原的清单VS2022 打开时会提示「还原 NuGet 包」点还原后packages\FluentFTP.45.1.0才会真正落地。参数说明targetFrameworknet48对应项目属性里的目标框架如果客户机器只装了 .Net Framework 4.7.2要么改项目目标框架要么让客户装 4.8 运行时这一步不确认后面编译报「找不到 FluentFTP」的概率极高。HintPath里的net45是 FluentFTP 45.1.0 的兼容目录别手动改成net48那个目录不存在。2.3 首次连接与 App.config 参数外置App.config里通常放 FTP 地址、账号、超时这些易变项实例里也是这么做的。把连接参数写死在代码里换个客户就要重新编译这是血泪经验。!-- App.config把环境相关参数抽出来 -- appSettings add keyFtpHost value192.168.1.100 / add keyFtpPort value21 / add keyFtpUser valueftpuser / add keyFtpPass value****** / add keyFtpTimeoutMs value15000 / /appSettings// FtpHelper.cs 里读取配置并建连的核心片段 public AsyncFtpClient CreateClient() { var host ConfigurationManager.AppSettings[FtpHost]; var port int.Parse(ConfigurationManager.AppSettings[FtpPort]); var user ConfigurationManager.AppSettings[FtpUser]; var pass ConfigurationManager.AppSettings[FtpPass]; var timeout int.Parse(ConfigurationManager.AppSettings[FtpTimeoutMs]); var client new AsyncFtpClient(host, user, pass, port); client.Config.ConnectTimeout timeout; // 连接超时产线建议 10~15 秒 client.Config.ReadTimeout timeout; // 读超时大文件别设太小 client.Config.DataConnectionType FtpDataConnectionType.AutoPassive; // 被动模式优先 return client; }逻辑说明AsyncFtpClient构造函数吃 host、user、pass、port 四个参数Config属性是 FluentFTP 的调参入口。参数说明ConnectTimeout控制 TCP 建连阶段ReadTimeout控制数据通道读写产线网络差的时候这两个值要分开调别一刀切。DataConnectionType设成AutoPassive是关键很多厂内 FTP 服务器在 NAT 后面主动模式连不上被动模式才能通。这一步跑通MainForm里点「连接」按钮能拿到目录列表环境就算立住了。3. FtpHelper 封装拆解上传下载、进度回调与断点续传3.1 FtpHelper 的职责边界与接口设计FtpHelper.cs是这个实例的核心它把 FluentFTP 的调用包了一层对外只暴露「上传文件」「下载文件」「列目录」「删文件」几个方法WinForm 的MainForm不直接碰AsyncFtpClient。这么设计的好处是换库、加日志、加重试都只改一个文件。我一般会把 Helper 做成非静态类每个操作内部using一个 client避免长连接在产线断网后变成僵尸连接。// FtpHelper.cs上传方法带进度回调 public async Taskbool UploadFileAsync(string localPath, string remotePath, IProgressFtpProgress progress null) { using (var client CreateClient()) { await client.Connect(); // FtpRemoteExists.Overwrite同名覆盖Skip 则跳过 var status await client.UploadFile(localPath, remotePath, FtpRemoteExists.Overwrite, true, progress); await client.Disconnect(); return status FtpStatus.Success; } }逻辑说明UploadFile的第三个参数FtpRemoteExists.Overwrite决定同名文件怎么处理第四个参数true表示创建远程目录如果 remotePath 带子目录。参数说明progress是IProgressFtpProgressFluentFTP 在传输过程中会往里推FtpProgress里面有Progress0~100 的 double和TransferredBytes。WinForm 里用ProgressT构造时传入 UI 线程的 SynchronizationContext回调就能直接更新进度条不用自己Invoke。3.2 进度回调接到 WinForm 进度条FtpElementControl这个自定义控件里应该封装了进度条和状态标签MainForm调用时把进度转过去。这是 WinForm 里最容易翻车的地方在后台线程直接改控件属性轻则界面不刷新重则抛跨线程异常。// MainForm.cs把 FtpProgress 映射到进度条 private async void btnUpload_Click(object sender, EventArgs e) { var progress new ProgressFtpProgress(p { // ProgressT 自动回到创建它的 UI 线程 progressBar.Value (int)p.Progress; lblStatus.Text $已传输 {p.TransferredBytes / 1024} KB; }); var helper new FtpHelper(); bool ok await helper.UploadFileAsync( txtLocalPath.Text, txtRemotePath.Text, progress); lblStatus.Text ok ? 上传完成 : 上传失败; }逻辑说明ProgressT在构造时捕获当前线程的SynchronizationContextWinForm 主线程有这个上下文所以回调自动切回 UI 线程。参数说明p.Progress是 double直接转 int 给progressBar.Value注意进度条Maximum默认 100别设成别的值。如果不用ProgressT而是自己开Task.Run再Invoke代码量翻倍还容易漏。这一步是 c# winform 如何更新状态栏与进度条这个热搜问题的标准答案。3.3 断点续传与重试参数怎么设产线传大文件断一次从头来谁都受不了。FluentFTP 的DownloadFile和UploadFile支持续传但要显式开。// 下载带断点续传本地已存在部分文件时从断点继续 var status await client.DownloadFile( localPath, remotePath, FtpLocalExists.Overwrite, // 本地同名文件处理策略 FtpVerify.Retry, // 传完校验失败重试 progress); // 全局重试次数放在 Config 上 client.Config.RetryAttempts 3;逻辑说明FtpVerify.Retry表示传输完成后做校验校验不过自动重试重试次数由RetryAttempts控制。参数说明FtpLocalExists.Overwrite会覆盖本地文件如果要做续传得用FtpLocalExists.Resume部分版本叫法不同以 45.1.0 的枚举为准它会检查本地文件大小从断点位置继续拉。RetryAttempts别设太大3 次够了设 10 次在服务器真挂的时候会卡很久。这里有个玄学某些 FTP 服务器不支持REST命令续传会直接失败遇到这种只能关掉续传老老实实重传。4. 避坑与排查FluentFTP 在 WinForm 里的五个真实翻车点4.1 现象连接一直卡住不返回界面假死原因Connect()是同步阻塞调用直接在 UI 线程调网络不通时界面就冻住。解决所有 FTP 操作走async/awaitMainForm里用await helper.UploadFileAsync(...)Helper 内部用AsyncFtpClient。如果非要用同步版至少丢到Task.Run里别在按钮点击事件里裸调。4.2 现象报 425 Cannot open data connection原因主动/被动模式不匹配或者服务器在 NAT 后没配好被动端口范围。解决Config.DataConnectionType设成AutoPassive还不行就试Passive。如果服务器端能配让它开放一段被动端口并在防火墙上放行客户端这边调不了。4.3 现象中文文件名上传后变乱码原因FluentFTP 默认用 UTF-8 发文件名但老 FTP 服务器只认 GBK。解决client.Config.Encoding Encoding.GetEncoding(GBK);在连接前设好。这个坑在国产工控设备上特别常见日志里看着文件名对服务器上就是问号。4.4 现象进度回调不触发进度条一直 0原因UploadFile的progress参数传了 null或者用了同步版方法。解决确认传了IProgressFtpProgress实例且用的是UploadFile的异步重载。另外进度回调频率和文件大小有关小文件可能直接跳到 100这是正常的。4.5 现象传完文件大小对不上服务器端文件损坏原因传输模式不对文本模式传二进制文件会做换行转换。解决FluentFTP 默认二进制模式一般不用管但如果服务器强制 ASCII要在Config里确认DataConnectionType和传输类型。更常见的是磁盘满或权限不足传一半断了但状态返回成功所以FtpVerify.Retry这个校验别省。5. 进阶把 FtpHelper 做成可复用组件与验证清单5.1 从 Demo 到产线组件的三步改造这份实例的FtpHelper是能直接用的但要上产线我一般会做三件事。第一加日志。FluentFTP 有client.Logger接口接一个写文件的实现每次连接、每条命令都记下来出问题不用猜。第二加取消支持。AsyncFtpClient的方法大多有CancellationToken重载WinForm 上加个「取消」按钮传 token 进去用户不用等传完。第三把配置从App.config挪到界面可编辑产线调试时不用改配置文件重启。// 接一个简单日志排查时能看清每条 FTP 命令 public class FtpFileLogger : IFtpLogger { private readonly string _path; public FtpFileLogger(string path) { _path path; } public void Log(FtpLogEntry entry) { File.AppendAllText(_path, ${DateTime.Now:HH:mm:ss} [{entry.Severity}] {entry.Message}\r\n); } } // 建连时挂上 client.Logger new FtpFileLogger(C:\Logs\ftp.log);逻辑说明IFtpLogger是 FluentFTP 暴露的日志接口FtpLogEntry里有Severity、Message、Exception等字段。参数说明日志路径别放系统盘根目录产线机器可能没写权限放C:\Logs或程序目录下。挂上日志后425、530、550 这些错误码对应的具体命令一目了然比抓包快。5.2 上线前的验证清单传完不算完得验。我习惯按这个顺序过一遍先传一个 0 字节文件确认服务器接受空文件再传一个 1MB 左右的小文件看进度回调是否连续然后传一个 500MB 以上的大文件中途拔网线看续传和重试是否生效最后传一个带中文名和空格的路径确认编码和转义没问题。这四步走完基本能覆盖产线 90% 的异常场景。验证项操作预期结果空文件上传 0 字节 txt服务器出现同名 0 字节文件小文件进度上传 1MB 文件进度条从 0 平滑到 100断网续传传大文件中途断网恢复后从断点继续不从头传中文路径上传「测试 文件.txt」服务器文件名不乱码5.3 一个具体技巧用 FtpListItem 做目录树MainForm里如果要展示远程目录树别自己拼字符串。FluentFTP 的GetListing返回FtpListItem[]里面有TypeFile/Directory、Size、Modified、Name直接绑到TreeView或ListView就行。递归列目录用GetListing(path, FtpListOption.Recursive)一次拿全比一层层调快得多。注意递归在目录很深的时候会慢产线服务器目录层级一般不深够用。// 递归列目录绑到 TreeView var items await client.GetListing(/data, FtpListOption.Recursive); foreach (var item in items) { if (item.Type FtpObjectType.Directory) treeView.Nodes.Add(item.FullName); }逻辑说明FtpListOption.Recursive让 FluentFTP 自己递归返回扁平列表FullName是完整路径。参数说明如果只要当前层去掉Recursive就行。item.Type判断是文件还是目录别用Size 0判断空目录 Size 也是 0。从那以后我每次接 FTP 相关的活都先把FtpHelper的日志和取消支持加上再按那份四步清单跑一遍宁可多花半小时验证也不想半夜被产线电话叫起来查 425。这套 DemoFtp 实例的价值不在代码多复杂在于它把 FluentFTP 在 WinForm 里最容易翻车的地方都趟过一遍你拿去改改就能用。希望帮到你。本文还有配套的精品资源点击获取
返回列表