2019独角兽企业重金招聘Python工程师标准>>>

一、写在前面

最近工作中遇到了一个场景,要用C#客户端访问FTP服务器,并实现文件下载功能。之前我使用了一种非常简单粗暴的方法,因为客户端之前就用到了Xilium.CefGlue(可以理解为一个WebKit内核)来实现浏览网页的功能,客户的需求又仅停留在登录FTP对部分压缩包和doc文件进行下载,我索性直接建了个页面,用这个WebKit内核实现对FTP进行访问,效果和Chrome浏览器访问FTP相似。

不过,这个方法有下面三个缺点:

1、Xilium.CefGlue类库占用的空间很大,如果就为了实现客户端访问FTP服务器,放入一个WebKit内核,平白增加了几十MB的空间占用,是非常不划算的。

2、Xilium.CefGlue打开FTP类似Chrome的打开方式,遇到txt、sql等扩展名的文件时,会直接在浏览器中打开,遇到pdf扩展名的文件时,会使用相关插件打开(或因无相关处理工具而进入错误页)。遇到其他扩展名的文件时,如exe、rar、zip、doc等,才会提示下载。

3、无法满足许多用户定制化的需求(虽然内核是开源的,但你敢改么?)。

所以说,使用C#客户端访问FTP服务器,最好的办法还是自己写一套工具类,实现FTP协议下的上传、下载、创建目录、查询目录下文件列表等操作。

二、使用Serv-U建立本地FTP

使用Serv-U工具可以在本机自建一个FTP服务,方法如下:

1、安装Serv-U并注册(试用版可以使用30天,我用的版本是10.3.0.1)

2、找到“新建域”按钮,新建一个FTP服务

3、新建域向导第一步:建立FTP域名,填写说明信息

4、新建域向导第二步:设置各协议端口号,一般来说使用默认端口号即可

4、新建域向导第三步:也使用默认设置

5、新建域向导第四步:设置密码加密模式,选择“使用服务器设置”

6、Serv-U询问是否要建立用户,点击“是”即可

7、建立用户向导第一步:设置用户登录ID为tsybius

8、建立用户向导第二步:设置密码,这里设置为123456

9、建立用户向导第三步:设置用户登录FTP后看到的根目录

10、建立用户向导第四步:设置访问权限,有只读访问和完全访问两种,这里我选择了完全访问

11、FTP建立完毕,在浏览器地址栏(或资源管理器地址栏)输入下面地址即可登录FTP:

ftp://tsybius:123456@localhost/

三、使用C#程序访问FTP

一般来说,使用C#程序访问FTP,只需要支持以下几个功能就足够了:

1、给定FTP下某一目录地址,获取该地址下所有的文件和目录及它们的详细信息

2、向FTP上传文件

3、从FTP下载文件

4、其他辅助功能(如刷新等)

我们要实现的功能可以参考Xftp,即XShell打开的FTP访问工具

C#中调用FTP的方法是相似的,如获取指定目录下所有文件的详细信息可以写成:

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;namespace FTPManager
{class FtpHelper{public static FtpFileInfo[] GetFtpFileInfos(string ftpPath, string userName, string passWord){LinkedList<FtpFileInfo> linkedList = new LinkedList<FtpFileInfo>();var reqFtp = (FtpWebRequest)WebRequest.Create(new Uri(ftpPath));reqFtp.UsePassive = false;reqFtp.UseBinary = true;//reqFTP.EnableSsl = true;//加密方式传送数据 FTP 服务器要支持reqFtp.Credentials = new NetworkCredential(userName, passWord);reqFtp.Method = WebRequestMethods.Ftp.ListDirectoryDetails;var response = (FtpWebResponse)reqFtp.GetResponse();var reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);string fileDetail = reader.ReadLine();while (fileDetail != null){linkedList.AddLast(new FtpFileInfo(fileDetail));fileDetail = reader.ReadLine();}reader.Close();response.Close();return linkedList.ToArray();}}
}

其中FtpFileInfo是我设计的一个用于管理FTP文件信息的类。下面贴出的代码只是一个非常简陋的版本,并没有经过多少测试,不过可被看做一个解决问题的思路:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace FTPManager
{public class FtpFileInfo{public string UnixFileType { get; set; }public string Permission { get; set; }public string NumberOfHardLinks { get; set; }public string Owner { get; set; }public string Group { get; set; }public string Size { get; set; }public string LastModifiedDate { get; set; }public string FileName { get; set; }public string FileDetail { get; set; }public FtpFileInfo(string fileDetail){this.FileDetail = fileDetail;int counter = 1;string[] propertyBlocks = fileDetail.Split(' ');foreach (string propertyBlock in propertyBlocks){switch (counter){case 1:{//unix file types & permissionsif (string.IsNullOrWhiteSpace(propertyBlock)){continue;}else{if (propertyBlock.Length == 10){UnixFileType = propertyBlock[0].ToString();Permission = propertyBlock.Substring(1);}counter++;}}break;case 2: {//number of hard linksif (string.IsNullOrWhiteSpace(propertyBlock)){continue;}else{NumberOfHardLinks = propertyBlock;counter++;}}break;case 3:{//ownerif (string.IsNullOrWhiteSpace(propertyBlock)){continue;}else{Owner = propertyBlock;counter++;}}break;case 4:{//groupif (string.IsNullOrWhiteSpace(propertyBlock)){continue;}else{Group = propertyBlock;counter++;}}break;case 5:{//sizeif (string.IsNullOrWhiteSpace(propertyBlock)){continue;}else{Size = propertyBlock;counter++;}}break;case 6:case 7:case 8:{//last-modified dateif (string.IsNullOrWhiteSpace(propertyBlock)){continue;}else{LastModifiedDate += propertyBlock + " ";counter++;}}break;case 9:{//file nameif (string.IsNullOrWhiteSpace(propertyBlock)){FileName += " ";}else{FileName += propertyBlock;}}break;}}LastModifiedDate = LastModifiedDate.Trim();FileName = FileName.Trim();}}
}

根据reqFtp.Method的不同,返回的流内容也会不同,我们需要对返回流的内容进行解析。reqFtp.Method一共支持以下几种枚举类型:

// 摘要:
//     表示可与 FTP 请求一起使用的 FTP 协议方法的类型。无法继承此类。
public static class Ftp
{// 摘要://     表示要用于将文件追加到 FTP 服务器上的现有文件的 FTP APPE 协议方法。public const string AppendFile = "APPE";//// 摘要://     表示要用于删除 FTP 服务器上的文件的 FTP DELE 协议方法。public const string DeleteFile = "DELE";//// 摘要://     表示要用于从 FTP 服务器下载文件的 FTP RETR 协议方法。public const string DownloadFile = "RETR";//// 摘要://     表示要用于从 FTP 服务器上的文件检索日期时间戳的 FTP MDTM 协议方法。public const string GetDateTimestamp = "MDTM";//// 摘要://     表示要用于检索 FTP 服务器上的文件大小的 FTP SIZE 协议方法。public const string GetFileSize = "SIZE";//// 摘要://     表示获取 FTP 服务器上的文件的简短列表的 FTP NLIST 协议方法。public const string ListDirectory = "NLST";//// 摘要://     表示获取 FTP 服务器上的文件的详细列表的 FTP LIST 协议方法。public const string ListDirectoryDetails = "LIST";//// 摘要://     表示在 FTP 服务器上创建目录的 FTP MKD 协议方法。public const string MakeDirectory = "MKD";//// 摘要://     表示打印当前工作目录的名称的 FTP PWD 协议方法。public const string PrintWorkingDirectory = "PWD";//// 摘要://     表示移除目录的 FTP RMD 协议方法。public const string RemoveDirectory = "RMD";//// 摘要://     表示重命名目录的 FTP RENAME 协议方法。public const string Rename = "RENAME";//// 摘要://     表示将文件上载到 FTP 服务器的 FTP STOR 协议方法。public const string UploadFile = "STOR";//// 摘要://     表示将具有唯一名称的文件上载到 FTP 服务器的 FTP STOU 协议方法。public const string UploadFileWithUniqueName = "STOU";
}

更详细的说明可参考MSDN页面:https://msdn.microsoft.com/zh-cn/library/ms144320.aspx

前面代码中使用到的是WebRequestMethods.Ftp.ListDirectoryDetails,因此返回流的内容为

返回的内容和Linux中命令“ls -l”是一样的,从左到右依次是:

Unix file types(Unix文件类型)、permissions(各用户权限)、number of hard links(硬连接数)、owner(所有者)、group(所属组)、size(文件大小)、last-modified date(文件最后更改时间)、filename(文件名)

关于Linux中ls命令的细节,可以参考维基百科页面:https://en.wikipedia.org/wiki/Ls

在主窗体下,写如下代码即可调用我们刚才实现的FtpHelper.GetFtpFileInfos:

private void FormMain_Load(object sender, EventArgs e)
{try{FtpFileInfo[] ftpFileInfos = FtpHelper.GetFtpFileInfos("ftp://localhost/", "tsybius", "123456");dgvFileList.DataSource = ftpFileInfos;}catch (Exception ex){MessageBox.Show(ex.Message);}
}

(其中dgvFileList为一个DataGridView控件)

代码执行效果如下:

上面代码应注意之处有:

1、DataGridView的相关样式设定这里不再赘述,我手动添加了四列,并为每列设置了DataPropertyName与FtpFileInfo字段相对应。

2、可以看出直接显示在DataGridView上的内容并不适合人阅读,文件类型、文件大小可以通过自己写两个继承自DataGridViewTextBoxColumn的类来实现令人舒服一些的显示。

3、上面的例子中,我们把数组传入DataGridView的DataSource,这样做有一个弊端是不能点击各列列头对数据进行排序。如果希望对数据排序,可将结果集转换成DataTable格式。

另附上我在网上找的几段C#访问FTP的代码,可供参考:

http://blog.csdn.net/chr23899/article/details/41787863

http://www.cnblogs.com/wang726zq/archive/2012/07/30/ftp.html

END

转载于:https://my.oschina.net/Tsybius2014/blog/714851

使用C#客户端访问FTP服务的一个解决方案相关推荐

  1. OAuth2授权客户端访问资源服务

    OAuth客户端访问资源服务 一.简介 在单点登录一文,我们是通过注解@EnableOAuth2Sso实现单点登录的,我们了解到OAuth2获取token的方式是通过OAuth2RestOperati ...

  2. Win7上防火墙开放FTP服务以及ping解决方案

    Win7上防火墙开放FTP服务以及ping解决方案 参考文章: (1)Win7上防火墙开放FTP服务以及ping解决方案 (2)https://www.cnblogs.com/laobiao/p/59 ...

  3. Linux搭建FTP,并使用Windows和IE浏览器访问FTP服务

    一. FTP详解 FTP(File Transfer Protocol):文件传输协议 目的:共享文件 作用:提供各主机之间文件共享服务,可以应用在互联网中,实现外地登陆服务器下载公司文件功能,不区分 ...

  4. FTP服务基础与如何设置匿名访问FTP服务

    文章目录 1.FTP(文件传输协议)概述 2.FTP工作模式 2.1 主动模式port 2.2 被动模式pasv 3.FTP传输模式 3.1 ASCⅢ传输模式 3.2 二进制传输模式 4.匿名访问的F ...

  5. 计算机无法访问ftp站点,为什么我的电脑无法访问FTP服务

    局域网内计算机访问FTP服务器时,提示"无法访问服务器名称或地址",一般由三个原因造成: 一.防火墙未关闭 解决方法如下: 1.单击屏幕左下角的"开始"菜单 2 ...

  6. win7开启ftp被动模式_Win7上防火墙开放FTP服务以及ping解决方案

    1.windows 防火墙开放ftp服务 The following 4 steps will allow both non-secure and SSL FTP traffic through fi ...

  7. 资源管理器方法访问FTP服务

    老方最近换了工作,做了乙方的项目经理,但技术实施的活也是要做的哈. 说话,最近在一个部队做项目,项目之外,协助他们建立了一个FTP服务器,权限什么的设置凭着老方的通天晓地(板砖,你慢慢的拍)的能耐,很 ...

  8. 外网访问FTP服务,解决只能以POST模式访问Filezilla的问题

    在内网可以正常使用PASV,但是在外网不行,导致数据传输慢或者根本连接不了,在FlashFXP中通过日志,找到了解决方法 解决方法 1.在Filezilla--Edit--Settings--Pass ...

  9. 云服务器安装ftp服务端,客户端无法访问

    目录 安装ftp 创建ftp登录用户 设置vsftpd.conf文件 简介 配置有弹性公网IP的Linux云服务器搭建FTP服务端后,FTP客户端访问FTP服务端可能会报错显示云服务器的内网IP或没响 ...

最新文章

  1. 什么是智能仓储?一文带你彻底搞懂!
  2. android串口通讯奇偶校验,串口通讯奇偶数校验及CRC校验如何使用详解
  3. Qt 通过鼠标移动窗口
  4. Codeforces Round #506 (Div. 3) - C. Maximal Intersection (思维,模拟)
  5. MyBatis注解模式取参数方法
  6. ssl初一组周六模拟赛【2018.4.21】
  7. 域名发散--前端优化(三)
  8. 解决金蝶未检测到K/3许可文件,并且该账套已超过演示版期限问题
  9. 推荐游戏玩家使用金山密保保护帐号安全
  10. web前端三大主流框架
  11. Xilinx平台SRIO介绍(六)SRIO收发测试
  12. 实战干货 | 这位成功转型机器学习的老炮,想把他多年的经验分享给你
  13. 给wordpess博客的数据库减肥提速
  14. win10无法防问其他计算机没有权限,Win10无internet访问权限怎么解决?
  15. 一文读懂keepalive的工作原理
  16. 二级渠道分销系统开发适合什么样的产品?
  17. mongoose的删除和修改
  18. python读取文件报错:‘utf-8‘ 或“gbk” codec can‘t decode byte 0xbe in position 627: invalid start byte
  19. 黑苹果Yosemite 10.10.1懒人版完美安装及简单驱动设置
  20. 烟雨白银坨_SAP刘梦_新浪博客

热门文章

  1. python excel案例导入jira_Python操作Jira库常用方法解析
  2. android 键盘遮盖输入框_Android软键盘遮住输入框的解决方法终极适配
  3. python中怎么求标准差_python 标准差计算的实现(std)
  4. Teamcenter 开发利器组合介绍。 Eclipse + Visual Studio
  5. 代理ip网站开发_网站反爬虫策略,用代理IP都能解决吗?
  6. 手机html文档,手机文档html能删除吗
  7. 精品网站 mysql,【网址导航系统】基于PHP+MYSQL开发的开源网站分类目录管理系统...
  8. Python中使用xpath获取select option的每一行的text和value
  9. python getsize_Python getsizeof()和getsize()区分详解
  10. mybatis mysql 配置文件路径_从零搭建SpringBoot+MyBatis+MySQL工程