jjzjj

C# 利用FluentFTP实现FTP上传下载功能

老码识途 2023-03-28 原文

FTP作为日常工作学习中,非常重要的一个文件传输存储空间,想必大家都非常的熟悉了,那么如何快速的实现文件的上传下载功能呢,本文以一个简单的小例子,简述如何通过FluentFTP实现文件的上传和下载功能。仅供学习分享使用,如有不足之处,还请指正。

FTP基础知识

文件传输协议(File Transfer Protocol,FTP)是用于在网络上进行文件传输的一套标准协议,它工作在 OSI 模型的第七层, TCP 模型的第四层, 即应用层, 使用 TCP 传输而不是 UDP, 客户在和服务器建立连接前要经过一个“三次握手”的过程, 保证客户与服务器之间的连接是可靠的, 而且是面向连接, 为数据传输提供可靠保证。FTP允许用户以文件操作的方式(如文件的增、删、改、查、传送等)与另一主机相互通信。然而, 用户并不真正登录到自己想要存取的计算机上面而成为完全用户, 可用FTP程序访问远程资源, 实现用户往返传输文件、目录管理以及访问电子邮件等等, 即使双方计算机可能配有不同的操作系统和文件存储方式。

FTP环境搭建

在windows操作系统中,FTP可以通过(Internet Inforamtion Services, IIS)管理器进行创建,创建成功后即可进行查看,如下所示:

 

FluentFTP安装

FluentFTP是一款基于.Net的FTP和FTPS的客户端动态库,操作简单便捷。

 

 

首先创建基于.Net Framework 4.6.1的winform应用程序,然后通过Nuget包管理器进行安装,如下所示:

 

示例演示

 主要实现基于FTP的上传,下载,浏览等功能,如下所示:

 

 进入文件夹及右键下载,如下所示:

 

示例源码

FtpHelper类源码,封装了FTP文件的检索,上传,下载等功能,如下所示:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.IO;
  4 using System.Linq;
  5 using System.Net;
  6 using System.Text;
  7 using System.Threading;
  8 using System.Threading.Tasks;
  9 using FluentFTP;
 10 
 11 namespace DemoFtp
 12 {
 13     public class FtpHelper
 14     {
 15         #region 属性与构造函数
 16 
 17         /// <summary>
 18         /// IP地址
 19         /// </summary>
 20         public string IpAddr { get; set; }
 21 
 22         /// <summary>
 23         /// 相对路径
 24         /// </summary>
 25         public string RelatePath { get; set; }
 26 
 27         /// <summary>
 28         /// 端口号
 29         /// </summary>
 30         public int Port { get; set; }
 31 
 32         /// <summary>
 33         /// 用户名
 34         /// </summary>
 35         public string UserName { get; set; }
 36 
 37         /// <summary>
 38         /// 密码
 39         /// </summary>
 40         public string Password { get; set; }
 41 
 42         public FtpHelper()
 43         {
 44 
 45         }
 46 
 47         public FtpHelper(string ipAddr, int port, string userName, string password, string relatePath)
 48         {
 49             this.IpAddr = ipAddr;
 50             this.Port = port;
 51             this.UserName = userName;
 52             this.Password = password;
 53             this.RelatePath = relatePath;
 54         }
 55 
 56         #endregion
 57 
 58         #region 方法
 59 
 60         public FtpListItem[] ListDir() {
 61             FtpListItem[] lists;
 62             using (var ftpClient = new FtpClient(this.IpAddr, this.UserName, this.Password, this.Port))
 63             {
 64                 ftpClient.Connect();
 65                 ftpClient.SetWorkingDirectory(this.RelatePath);
 66                 lists = ftpClient.GetListing();
 67             }
 68             return lists;
 69         }
 70 
 71         public void UpLoad(string dir, string file, out bool isOk)
 72         {
 73             isOk = false;
 74             FileInfo fi = new FileInfo(file);
 75             using (FileStream fs = fi.OpenRead())
 76             {
 77                 //long length = fs.Length;
 78                 using (var ftpClient = new FtpClient(this.IpAddr, this.UserName, this.Password, this.Port))
 79                 {
 80                     ftpClient.Connect();
 81                     ftpClient.SetWorkingDirectory(this.RelatePath);
 82                     string remotePath = dir + "/" + Path.GetFileName(file);
 83                     var ftpRemodeExistsMode = file.EndsWith(".txt") ? FtpRemoteExists.Overwrite : FtpRemoteExists.Skip;
 84                     FtpStatus status = ftpClient.UploadStream(fs, remotePath, ftpRemodeExistsMode, true);
 85                     isOk = status == FtpStatus.Success;
 86 
 87                 }
 88             }
 89          
 90         }
 91 
 92         /// <summary>
 93         /// 上传多个文件
 94         /// </summary>
 95         /// <param name="files"></param>
 96         /// <param name="isOk"></param>
 97         public void UpLoad(string dir, string[] files, out bool isOk)
 98         {
 99             isOk = false;
100             if (CheckDirIsExists(dir))
101             {
102                 foreach (var file in files)
103                 {
104                     UpLoad(dir, file, out isOk);
105                 }
106             }
107         }
108 
109 
110         private bool CheckDirIsExists(string dir)
111         {
112             bool flag = false;
113             using (var ftpClient = new FtpClient(this.IpAddr, this.UserName, this.Password, this.Port))
114             {
115                 ftpClient.Connect();
116                 ftpClient.SetWorkingDirectory(this.RelatePath);
117                 flag = ftpClient.DirectoryExists(dir);
118                 if (!flag)
119                 {
120                     flag = ftpClient.CreateDirectory(dir);
121                 }
122             }
123             return flag;
124 
125 
126         }
127 
128         /// <summary> 
129         /// 下载ftp 
130         /// </summary> 
131         /// <param name="localAddress"></param> 
132         /// <param name="remoteAddress"></param> 
133         /// <returns></returns> 
134         public bool DownloadFile(string localAddress, string remoteAddress)
135         {
136             using (var ftpClient = new FtpClient(this.IpAddr, this.UserName, this.Password, this.Port))
137             {
138                 ftpClient.SetWorkingDirectory("/");
139                 ftpClient.Connect();
140                 if (ftpClient.DownloadFile(localAddress, remoteAddress) == FtpStatus.Success)
141                 {
142                     return true;
143                 }
144                 return false;
145             }
146         }
147 
148         #endregion
149     }
150 }

每一个FTP文件或文件夹,由一个自定义用户控件【PictureBox+Label+ContextMenu】表示,这样便于处理与显示:

 1 using DemoFtp.Properties;
 2 using FluentFTP;
 3 using System;
 4 using System.Collections.Generic;
 5 using System.ComponentModel;
 6 using System.Data;
 7 using System.Drawing;
 8 using System.IO;
 9 using System.Linq;
10 using System.Text;
11 using System.Threading.Tasks;
12 using System.Windows.Forms;
13 
14 namespace DemoFtp
15 {
16     public partial class FtpElementControl : UserControl
17     {
18         public Action<FtpListItem> SubFolderClick;
19 
20         public Action<FtpListItem> DownLoadClick;
21 
22         private FtpListItem ftpListItem;
23 
24         public FtpElementControl(FtpListItem ftpListItem)
25         {
26             InitializeComponent();
27             this.ftpListItem = ftpListItem;
28         }
29 
30         public FtpElementControl()
31         {
32             InitializeComponent();
33         }
34 
35         public void InitControl()
36         {
37             if (ftpListItem.Type == FtpObjectType.Directory)
38             {
39                 this.pbIcon.Image = Resources.folder.ToBitmap();
40             }
41             else if (ftpListItem.Type == FtpObjectType.File)
42             {
43                 var name = ftpListItem.Name;
44                 var ext = Path.GetExtension(name).ToLower().Substring(1);
45                 if (ext == "png" || ext == "jpeg" || ext == "jpg" || ext == "bmp" || ext == "gif")
46                 {
47                     this.pbIcon.Image = Resources.pictures.ToBitmap();
48                 }
49                 else if (ext == "doc" || ext == "docx")
50                 {
51                     this.pbIcon.Image = Resources.doc.ToBitmap();
52                 }
53                 else if (ext == "exe")
54                 {
55                     this.pbIcon.Image = Resources.setup.ToBitmap();
56                 }
57                 else
58                 {
59                     this.pbIcon.Image = Resources.file;
60                 }
61             }
62             else
63             {
64                 this.pbIcon.Image = Resources.file;
65             }
66             this.lblName.Text = ftpListItem.Name;
67         }
68 
69         private void FtpElementControl_Load(object sender, EventArgs e)
70         {
71             
72         }
73 
74         /// <summary>
75         /// 子菜单下载功能
76         /// </summary>
77         /// <param name="sender"></param>
78         /// <param name="e"></param>
79         private void menu_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
80         {
81             this.DownLoadClick?.Invoke(ftpListItem);
82         }
83 
84         /// <summary>
85         /// 双击打开
86         /// </summary>
87         /// <param name="sender"></param>
88         /// <param name="e"></param>
89         private void pbIcon_DoubleClick(object sender, EventArgs e)
90         {
91             this.SubFolderClick?.Invoke(ftpListItem);
92         }
93     }
94 }

主页面由一系列用户操作框和按钮组成,完成对FTP的基本操作,如下所示:

  1 using FluentFTP;
  2 using System;
  3 using System.Collections.Generic;
  4 using System.ComponentModel;
  5 using System.Data;
  6 using System.Drawing;
  7 using System.IO;
  8 using System.Linq;
  9 using System.Text;
 10 using System.Threading.Tasks;
 11 using System.Windows.Forms;
 12 
 13 namespace DemoFtp
 14 {
 15     public partial class MainForm : Form
 16     {
 17         private FtpHelper ftpHelper;
 18 
 19         public MainForm()
 20         {
 21             InitializeComponent();
 22         }
 23 
 24         private void btnLogin_Click(object sender, EventArgs e)
 25         {
 26             var url = txtFtpUrl.Text;
 27             var userName = txtUserName.Text;
 28             var password = txtPassword.Text;
 29             var port = txtPort.Text;
 30             if (this.lblRelatePath.Text != "/")
 31             {
 32                 this.lblRelatePath.Text = "/";
 33             }
 34             var relatePath = this.lblRelatePath.Text;
 35             if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password) || string.IsNullOrEmpty(port))
 36             {
 37                 MessageBox.Show("路径和账号密码不可为空");
 38                 return;
 39             }
 40             if (ftpHelper == null)
 41             {
 42                 ftpHelper = new FtpHelper(url, int.Parse(port), userName, password, relatePath);
 43 
 44             }
 45             ListDir();
 46         }
 47 
 48         public void SubFolder(FtpListItem ftpListItem)
 49         {
 50             if (ftpListItem.Type == FtpObjectType.Directory)
 51             {
 52                 var fullName = ftpListItem.FullName;
 53                 ftpHelper.RelatePath = fullName;
 54                 ListDir();
 55                 this.lblRelatePath.Text = fullName;
 56             }
 57         }
 58 
 59 
 60         private void Download(FtpListItem ftpListItem) { 
 61             var fullName=ftpListItem.FullName;
 62             var fileName = Path.GetFileName(fullName);
 63             SaveFileDialog sfd = new SaveFileDialog();
 64             sfd.FileName = fileName;
 65             sfd.Title = "不载";
 66             sfd.Filter = "所有文档|*.*";
 67             if (DialogResult.OK == sfd.ShowDialog()) { 
 68                 ftpHelper.DownloadFile(sfd.FileName, fullName);
 69             }
 70         }
 71 
 72         private void ListDir()
 73         {
 74             this.ftpContainer.Controls.Clear();
 75             var ftpListItems = this.ftpHelper.ListDir();
 76             if (ftpListItems != null && ftpListItems.Length > 0)
 77             {
 78                 foreach (var ftpListItem in ftpListItems)
 79                 {
 80                     FtpElementControl ftpControl = new FtpElementControl(ftpListItem);
 81                     ftpControl.InitControl();
 82                     ftpControl.DownLoadClick += Download;
 83                     ftpControl.SubFolderClick += SubFolder;
 84                     this.ftpContainer.Controls.Add(ftpControl);
 85                 }
 86             }
 87         }
 88 
 89         private void btnUpload_Click(object sender, EventArgs e)
 90         {
 91             OpenFileDialog ofd = new OpenFileDialog();
 92             ofd.Filter = "所有文件|*.*";
 93             ofd.Title = "请选择需要上传的文件";
 94             if (DialogResult.OK == ofd.ShowDialog()) { 
 95                 var localFile=ofd.FileName;
 96                 ftpHelper.UpLoad(this.lblRelatePath.Text, localFile, out bool isOk);
 97                 if (isOk) {
 98                     ListDir();
 99                 }
100             }
101         }
102 
103         private void pbReturn_Click(object sender, EventArgs e)
104         {
105             var relativePath=this.lblRelatePath.Text;
106             if (relativePath == "/") {
107                 return;
108             }
109             relativePath = relativePath.Substring(0, relativePath.LastIndexOf("/")+1);
110             ftpHelper.RelatePath=relativePath;
111             ListDir();
112             this.lblRelatePath.Text = relativePath;
113         }
114     }
115 }

以上就是基于FluentFTP实现FTP上传下载的全部内容,旨在抛砖引玉,共同学习,一起进步。

有关C# 利用FluentFTP实现FTP上传下载功能的更多相关文章

  1. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

  2. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

  3. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  4. ruby - 安装 Ruby 时遇到问题(无法下载资源 "readline--patch") - 2

    当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub

  5. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  6. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  7. ruby-on-rails - Cucumber 是否只是 rspec 的包装器以帮助将测试组织成功能? - 2

    只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您

  8. ruby-on-rails - 添加回形针新样式不影响旧上传的图像 - 2

    我有带有Logo图像的公司模型has_attached_file:logo我用他们的Logo创建了许多公司。现在,我需要添加新样式has_attached_file:logo,:styles=>{:small=>"30x15>",:medium=>"155x85>"}我是否应该重新上传所有旧数据以重新生成新样式?我不这么认为……或者有什么rake任务可以重新生成样式吗? 最佳答案 参见Thumbnail-Generation.如果rake任务不适合你,你应该能够在控制台中使用一个片段来调用重新处理!关于相关公司

  9. ruby-on-rails - 有没有办法为 CarrierWave/Fog 设置上传进度指示器? - 2

    我在Rails应用程序中使用CarrierWave/Fog将视频上传到AmazonS3。有没有办法判断上传的进度,让我可以显示上传进度如何? 最佳答案 CarrierWave和Fog本身没有这种功能;你需要一个前端uploader来显示进度。当我不得不解决这个问题时,我使用了jQueryfileupload因为我的堆栈中已经有jQuery。甚至还有apostonCarrierWaveintegration因此您只需按照那里的说明操作即可获得适用于您的应用的进度条。 关于ruby-on-r

  10. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

随机推荐